From e2ee72b509a4ce0f6cbdf11c0130b1004a3f3f5a Mon Sep 17 00:00:00 2001 From: George Rimar Date: Fri, 26 Feb 2016 14:48:31 +0000 Subject: [PATCH] [ELF] - Implemented linkerscript sections padding. BSD linker scripts contain special cases to add NOP padding to code sections. Syntax is next: .init: { KEEP (*(.init)) } =0x90909090 (0x90 is NOP) This patch implements that functionality. llvm-svn: 262020 --- lld/ELF/LinkerScript.cpp | 60 ++++++++++++++++++++++++---- lld/ELF/LinkerScript.h | 11 ++++- lld/ELF/OutputSections.cpp | 11 +++++ lld/test/ELF/linkerscript-sections-padding.s | 44 ++++++++++++++++++++ 4 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 lld/test/ELF/linkerscript-sections-padding.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index a8e7119..a146be0 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -54,13 +54,22 @@ template bool LinkerScript::shouldKeep(InputSectionBase *S) { return R && R->Keep; } +ArrayRef LinkerScript::getFiller(StringRef Name) { + for (OutSection &C : OutSections) + if (C.Name == Name) + return C.Filler; + return {}; +} + // A compartor to sort output sections. Returns -1 or 1 if both // A and B are mentioned in linker scripts. Otherwise, returns 0 // to use the default rule which is implemented in Writer.cpp. int LinkerScript::compareSections(StringRef A, StringRef B) { - auto E = SectionOrder.end(); - auto I = std::find(SectionOrder.begin(), E, A); - auto J = std::find(SectionOrder.begin(), E, B); + auto E = OutSections.end(); + auto I = std::find_if(OutSections.begin(), E, + [&](OutSection &C) { return C.Name == A; }); + auto J = std::find_if(OutSections.begin(), E, + [&](OutSection &C) { return C.Name == B; }); if (I == E || J == E) return 0; return I < J ? -1 : 1; @@ -109,6 +118,7 @@ private: static StringRef skipSpace(StringRef S); bool atEOF(); StringRef next(); + StringRef peek(); bool skip(StringRef Tok); void expect(StringRef Expect); @@ -129,6 +139,8 @@ private: void readOutputSectionDescription(); void readSectionPatterns(StringRef OutSec, bool Keep); + std::vector parseHex(StringRef S); + StringSaver Saver; std::vector Tokens; const static StringMap Cmd; @@ -233,6 +245,14 @@ StringRef ScriptParser::next() { return Tokens[Pos++]; } +StringRef ScriptParser::peek() { + StringRef Tok = next(); + if (Error) + return ""; + --Pos; + return Tok; +} + bool ScriptParser::skip(StringRef Tok) { if (Error) return false; @@ -394,24 +414,50 @@ void ScriptParser::readSectionPatterns(StringRef OutSec, bool Keep) { Script->Sections.emplace_back(OutSec, next(), Keep); } +std::vector ScriptParser::parseHex(StringRef S) { + std::vector Hex; + while (!S.empty()) { + StringRef B = S.substr(0, 2); + S = S.substr(2); + uint8_t H; + if (B.getAsInteger(16, H)) { + setError("Not a HEX value: " + B); + return {}; + } + Hex.push_back(H); + } + return Hex; +} + void ScriptParser::readOutputSectionDescription() { - StringRef OutSec = next(); - Script->SectionOrder.push_back(OutSec); + OutSection OutSec; + OutSec.Name = next(); expect(":"); expect("{"); while (!Error && !skip("}")) { StringRef Tok = next(); if (Tok == "*") { - readSectionPatterns(OutSec, false); + readSectionPatterns(OutSec.Name, false); } else if (Tok == "KEEP") { expect("("); next(); // Skip * - readSectionPatterns(OutSec, true); + readSectionPatterns(OutSec.Name, true); expect(")"); } else { setError("Unknown command " + Tok); } } + StringRef Tok = peek(); + if (Tok.startswith("=")) { + if (!Tok.startswith("=0x")) { + setError("Filler should be a HEX value"); + return; + } + Tok = Tok.substr(3); // Skip '=0x' + OutSec.Filler = parseHex(Tok); + next(); + } + Script->OutSections.push_back(OutSec); } static bool isUnderSysroot(StringRef Path) { diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index 563e513..c534478 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -40,6 +40,11 @@ private: StringRef SectionPattern; }; +struct OutSection { + StringRef Name; + std::vector Filler; +}; + // This is a runner of the linker script. class LinkerScript { friend class ScriptParser; @@ -50,6 +55,7 @@ public: void read(MemoryBufferRef MB); template StringRef getOutputSection(InputSectionBase *S); + ArrayRef getFiller(StringRef Name); template bool isDiscarded(InputSectionBase *S); template bool shouldKeep(InputSectionBase *S); int compareSections(StringRef A, StringRef B); @@ -60,8 +66,9 @@ private: // SECTIONS commands. std::vector Sections; - // Output sections are sorted by this order. - std::vector SectionOrder; + // Output sections information. + // They are sorted by the order of the container. + std::vector OutSections; llvm::BumpPtrAllocator Alloc; }; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 5ed7cc0..472eda9 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -9,6 +9,7 @@ #include "OutputSections.h" #include "Config.h" +#include "LinkerScript.h" #include "SymbolTable.h" #include "Target.h" #include "llvm/Support/Dwarf.h" @@ -954,7 +955,17 @@ bool elf2::canBePreempted(const SymbolBody *Body) { return true; } +static void fill(uint8_t *Buf, size_t Size, ArrayRef A) { + size_t I = 0; + for (; I + A.size() < Size; I += A.size()) + memcpy(Buf + I, A.data(), A.size()); + memcpy(Buf + I, A.data(), Size - I); +} + template void OutputSection::writeTo(uint8_t *Buf) { + ArrayRef Filler = Script->getFiller(this->Name); + if (!Filler.empty()) + fill(Buf, this->getSize(), Filler); for (InputSection *C : Sections) C->writeTo(Buf); } diff --git a/lld/test/ELF/linkerscript-sections-padding.s b/lld/test/ELF/linkerscript-sections-padding.s new file mode 100644 index 0000000..eb2c919 --- /dev/null +++ b/lld/test/ELF/linkerscript-sections-padding.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +## Check that padding value works: +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x112233445566778899 }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES %s +# YES: 00000120 66 22 33 44 55 66 77 88 99 11 22 33 44 55 66 77 + +## Confirming that address was correct: +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x998877665544332211 }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: hexdump -C %t.out | FileCheck -check-prefix=YES2 %s +# YES2: 00000120 66 88 77 66 55 44 33 22 11 99 88 77 66 55 44 + +## Default padding value is 0x00: +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } }" > %t.script +# RUN: ld.lld -o %t.out --script %t.script %t +# RUN: hexdump -C %t.out | FileCheck -check-prefix=NO %s +# NO: 00000120 66 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +## Filler should be a hex value (1): +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =99 }" > %t.script +# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \ +# RUN: | FileCheck --check-prefix=ERR %s +# ERR: Filler should be a HEX value + +## Filler should be a hex value (2): +# RUN: echo "SECTIONS { .mysec : { *(.mysec*) } =0x99XX }" > %t.script +# RUN: not ld.lld -o %t.out --script %t.script %t 2>&1 \ +# RUN: | FileCheck --check-prefix=ERR2 %s +# ERR2: Not a HEX value: XX + +.section .mysec.1,"a" +.align 16 +.byte 0x66 + +.section .mysec.2,"a" +.align 16 +.byte 0x66 + +.globl _start +_start: + nop -- 2.7.4