Index: llvm/test/tools/llvm-elfabi/bin-to-bin.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-elfabi/bin-to-bin.test @@ -0,0 +1,13 @@ +# RUN: llvm-elfabi --elf %p/Inputs/gnu_hash.so --output-target=elf64-little %t +# RUN: llvm-nm -D %t | FileCheck %s + +# CHECK: AGlobalInteger +# CHECK-NEXT: AThreadLocalLongInteger +# CHECK-NEXT: _ITM_deregisterTMCloneTable +# CHECK-NEXT: _ITM_registerTMCloneTable +# CHECK-NEXT: _Z11rotateArrayPii +# CHECK-NEXT: __cxa_finalize +# CHECK-NEXT: __gmon_start__ +# CHECK-NEXT: __tls_get_addr +# CHECK-NEXT: _fini +# CHECK-NEXT: _init Index: llvm/test/tools/llvm-elfabi/binary-write-pheaders.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-write-pheaders.test +++ llvm/test/tools/llvm-elfabi/binary-write-pheaders.test @@ -8,7 +8,7 @@ Symbols: {} ... -# ELFHEADER: ProgramHeaderCount: 2{{$}} +# ELFHEADER: ProgramHeaderCount: 3{{$}} # PHDRS: ProgramHeader { # PHDRS-NEXT: Type: PT_LOAD (0x1) @@ -24,12 +24,26 @@ # PHDRS-NEXT: Alignment: 4096{{$}} # PHDRS-NEXT: } # PHDRS-NEXT: ProgramHeader { +# PHDRS-NEXT: Type: PT_LOAD (0x1) +# PHDRS-NEXT: Offset: {{.*$}} +# PHDRS-NEXT: VirtualAddress: {{.*$}} +# PHDRS-NEXT: PhysicalAddress: {{.*$}} +# PHDRS-NEXT: FileSize: 0{{$}} +# PHDRS-NEXT: MemSize: 0{{$}} +# PHDRS-NEXT: Flags [ (0x7) +# PHDRS-NEXT: PF_R (0x4) +# PHDRS-NEXT: PF_W (0x2) +# PHDRS-NEXT: PF_X (0x1) +# PHDRS-NEXT: ] +# PHDRS-NEXT: Alignment: 4096{{$}} +# PHDRS-NEXT: } +# PHDRS-NEXT: ProgramHeader { # PHDRS-NEXT: Type: PT_DYNAMIC (0x2) # PHDRS-NEXT: Offset: {{.*$}} # PHDRS-NEXT: VirtualAddress: {{.*$}} # PHDRS-NEXT: PhysicalAddress: {{.*$}} -# PHDRS-NEXT: FileSize: 48{{$}} -# PHDRS-NEXT: MemSize: 48{{$}} +# PHDRS-NEXT: FileSize: 80{{$}} +# PHDRS-NEXT: MemSize: 80{{$}} # PHDRS-NEXT: Flags [ (0x6) # PHDRS-NEXT: PF_R (0x4) # PHDRS-NEXT: PF_W (0x2) Index: llvm/test/tools/llvm-elfabi/binary-write-sheaders.test =================================================================== --- llvm/test/tools/llvm-elfabi/binary-write-sheaders.test +++ llvm/test/tools/llvm-elfabi/binary-write-sheaders.test @@ -8,8 +8,8 @@ Symbols: {} ... -# ELFHEADER: SectionHeaderCount: 4{{$}} -# ELFHEADER: StringTableSectionIndex: 3{{$}} +# ELFHEADER: SectionHeaderCount: 6{{$}} +# ELFHEADER: StringTableSectionIndex: 5{{$}} # SECTIONS: Section { # SECTIONS-NEXT: Index: 0{{$}} @@ -19,14 +19,29 @@ # SECTIONS-NEXT: ] # SECTIONS-NEXT: Address: 0x0{{$}} # SECTIONS-NEXT: Offset: 0x0{{$}} -# SECTIONS-NEXT: Size: 4{{$}} -# SECTIONS-NEXT: Link: 3{{$}} +# SECTIONS-NEXT: Size: 6{{$}} +# SECTIONS-NEXT: Link: 5{{$}} # SECTIONS-NEXT: Info: 0{{$}} # SECTIONS-NEXT: AddressAlignment: 0{{$}} # SECTIONS-NEXT: EntrySize: 0{{$}} # SECTIONS-NEXT: } # SECTIONS-NEXT: Section { # SECTIONS-NEXT: Index: 1{{$}} +# SECTIONS-NEXT: Name: .dynsym (9) +# SECTIONS-NEXT: Type: SHT_DYNSYM (0xB) +# SECTIONS-NEXT: Flags [ (0x2) +# SECTIONS-NEXT: SHF_ALLOC (0x2) +# SECTIONS-NEXT: ] +# SECTIONS-NEXT: Address: {{.*$}} +# SECTIONS-NEXT: Offset: {{.*$}} +# SECTIONS-NEXT: Size: 24{{$}} +# SECTIONS-NEXT: Link: 2{{$}} +# SECTIONS-NEXT: Info: 1{{$}} +# SECTIONS-NEXT: AddressAlignment: 8{{$}} +# SECTIONS-NEXT: EntrySize: 24{{$}} +# SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 2{{$}} # SECTIONS-NEXT: Name: .dynstr (1) # SECTIONS-NEXT: Type: SHT_STRTAB (0x3) # SECTIONS-NEXT: Flags [ (0x2) @@ -41,29 +56,46 @@ # SECTIONS-NEXT: EntrySize: 0{{$}} # SECTIONS-NEXT: } # SECTIONS-NEXT: Section { -# SECTIONS-NEXT: Index: 2{{$}} -# SECTIONS-NEXT: Name: .dynamic (9) +# SECTIONS-NEXT: Index: 3{{$}} +# SECTIONS-NEXT: Name: .dynamic (22) # SECTIONS-NEXT: Type: SHT_DYNAMIC (0x6) # SECTIONS-NEXT: Flags [ (0x2) # SECTIONS-NEXT: SHF_ALLOC (0x2) # SECTIONS-NEXT: ] # SECTIONS-NEXT: Address: {{.*$}} # SECTIONS-NEXT: Offset: {{.*$}} -# SECTIONS-NEXT: Size: 48{{$}} -# SECTIONS-NEXT: Link: 1{{$}} +# SECTIONS-NEXT: Size: 80{{$}} +# SECTIONS-NEXT: Link: 2{{$}} # SECTIONS-NEXT: Info: 0{{$}} # SECTIONS-NEXT: AddressAlignment: 8{{$}} # SECTIONS-NEXT: EntrySize: 16{{$}} # SECTIONS-NEXT: } # SECTIONS-NEXT: Section { -# SECTIONS-NEXT: Index: 3{{$}} -# SECTIONS-NEXT: Name: .shstrtab (18) +# SECTIONS-NEXT: Index: 4{{$}} +# SECTIONS-NEXT: Name: .def (17) +# SECTIONS-NEXT: Type: SHT_NOBITS (0x8) +# SECTIONS-NEXT: Flags [ (0x7) +# SECTIONS-NEXT: SHF_ALLOC (0x2) +# SECTIONS-NEXT: SHF_EXECINSTR (0x4) +# SECTIONS-NEXT: SHF_WRITE (0x1) +# SECTIONS-NEXT: ] +# SECTIONS-NEXT: Address: {{.*$}} +# SECTIONS-NEXT: Offset: {{.*$}} +# SECTIONS-NEXT: Size: 0{{$}} +# SECTIONS-NEXT: Link: 0{{$}} +# SECTIONS-NEXT: Info: 0{{$}} +# SECTIONS-NEXT: AddressAlignment: 16{{$}} +# SECTIONS-NEXT: EntrySize: 0{{$}} +# SECTIONS-NEXT: } +# SECTIONS-NEXT: Section { +# SECTIONS-NEXT: Index: 5{{$}} +# SECTIONS-NEXT: Name: .shstrtab (31) # SECTIONS-NEXT: Type: SHT_STRTAB (0x3) # SECTIONS-NEXT: Flags [ (0x0) # SECTIONS-NEXT: ] # SECTIONS-NEXT: Address: 0x0{{$}} # SECTIONS-NEXT: Offset: {{.*$}} -# SECTIONS-NEXT: Size: 28{{$}} +# SECTIONS-NEXT: Size: 41{{$}} # SECTIONS-NEXT: Link: 0{{$}} # SECTIONS-NEXT: Info: 0{{$}} # SECTIONS-NEXT: AddressAlignment: 1{{$}} Index: llvm/test/tools/llvm-elfabi/binary-write-symbols.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-elfabi/binary-write-symbols.test @@ -0,0 +1,77 @@ +# RUN: llvm-elfabi %s --output-target=elf64-little %t +# RUN: llvm-nm -D %t | FileCheck %s --check-prefix=NM +# RUN: llvm-readobj --dyn-symbols %t | FileCheck %s --check-prefix=READOBJ + +--- !tapi-tbe +TbeVersion: 1.0 +Arch: x86_64 +Symbols: + foo: { Type: TLS, Size: 24 } + bar: { Type: Object, Size: 42, Weak: true } + baz: { Type: Object, Size: 8, Undefined: true } + not: { Type: NoType, Undefined: true } + nor: { Type: Func } +... + +# NM: V bar +# NM-NEXT: U baz +# NM-NEXT: B foo +# NM-NEXT: B nor +# NM-NEXT: U not + +# READOBJ: DynamicSymbols [ +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: (0) +# READOBJ-NEXT: Value: 0x0 +# READOBJ-NEXT: Size: 0 +# READOBJ-NEXT: Binding: Local (0x0) +# READOBJ-NEXT: Type: None (0x0) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: Undefined (0x0) +# READOBJ-NEXT: } +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: bar (13) +# READOBJ-NEXT: Value: 0x1000 +# READOBJ-NEXT: Size: 42 +# READOBJ-NEXT: Binding: Weak (0x2) +# READOBJ-NEXT: Type: Object (0x1) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: .def (0x4) +# READOBJ-NEXT: } +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: baz (1) +# READOBJ-NEXT: Value: 0x0 +# READOBJ-NEXT: Size: 8 +# READOBJ-NEXT: Binding: Global (0x1) +# READOBJ-NEXT: Type: Object (0x1) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: Undefined (0x0) +# READOBJ-NEXT: } +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: foo (17) +# READOBJ-NEXT: Value: 0x1030 +# READOBJ-NEXT: Size: 24 +# READOBJ-NEXT: Binding: Global (0x1) +# READOBJ-NEXT: Type: TLS (0x6) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: .def (0x4) +# READOBJ-NEXT: } +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: nor (9) +# READOBJ-NEXT: Value: 0x1050 +# READOBJ-NEXT: Size: 0 +# READOBJ-NEXT: Binding: Global (0x1) +# READOBJ-NEXT: Type: Function (0x2) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: .def (0x4) +# READOBJ-NEXT: } +# READOBJ-NEXT: Symbol { +# READOBJ-NEXT: Name: not (5) +# READOBJ-NEXT: Value: 0x0 +# READOBJ-NEXT: Size: 0 +# READOBJ-NEXT: Binding: Global (0x1) +# READOBJ-NEXT: Type: None (0x0) +# READOBJ-NEXT: Other: 0 +# READOBJ-NEXT: Section: Undefined (0x0) +# READOBJ-NEXT: } +# READOBJ-NEXT: ] Index: llvm/tools/llvm-elfabi/ELFObjHandler.cpp =================================================================== --- llvm/tools/llvm-elfabi/ELFObjHandler.cpp +++ llvm/tools/llvm-elfabi/ELFObjHandler.cpp @@ -401,6 +401,21 @@ } +/// A simple function to initialize members of the .dynsym section header. +/// This function doesn't populate all of the section header members. The +/// members not explicitly populated are zero-initialized, and some members +/// (e.g. sh_size, sh_offset, and more) are populated later. +template +static void initDynSymShdr(typename ELFT::Shdr &DynSym) { + using Elf_Sym = typename ELFT::Sym; + memset(&DynSym, 0, sizeof(typename ELFT::Shdr)); + DynSym.sh_type = SHT_DYNSYM; + DynSym.sh_flags = SHF_ALLOC; + DynSym.sh_entsize = sizeof(Elf_Sym); + DynSym.sh_addralign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + DynSym.sh_info = 1; +} + /// A simple function to initialize members of the .dynstr section header. /// This function doesn't populate all of the section header members. The /// members not explicitly populated are zero-initialized, and some members @@ -424,6 +439,19 @@ ShStrTabHdr.sh_addralign = 1; } +/// A simple function to initialize members of the .def section header. +/// This function doesn't populate all of the section header members. The +/// members not explicitly populated are zero-initialized, and some members +/// (e.g. sh_size, sh_offset, and more) are populated later. +template +static void initDefShdr(typename ELFT::Shdr &DefHdr) { + memset(&DefHdr, 0, sizeof(typename ELFT::Shdr)); + DefHdr.sh_type = SHT_NOBITS; + DefHdr.sh_flags = SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR; + size_t Align = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + DefHdr.sh_addralign = Align * 2; +} + /// A simple function to initialize members of the PT_DYNAMIC program header. /// This function doesn't populate all of the program header members. The /// members not explicitly populated are zero-initialized, and some members @@ -451,6 +479,18 @@ LoadPhdr.p_align = 0x1000; } +/// A simple helper function to zero-pad a buffer to the next alignment. +/// +/// @return Aligned offset. +static size_t padAndAlign(uint8_t *Dest, size_t Offset, size_t Align) { + size_t OffsetPad = alignTo(Offset, Align) - Offset; + if (OffsetPad != 0) { + memset(Dest + Offset, 0, OffsetPad); + Offset += OffsetPad; + } + return Offset; +} + /// A simple helper function to align an offset/address. /// /// @return Aligned offset. @@ -497,6 +537,9 @@ for (const std::string &LibName : Stub.NeededLibs) { DynStrTab.add(LibName); } + for (const ELFSymbol &Sym : Stub.Symbols) { + DynStrTab.add(Sym.Name); + } DynStrTab.finalize(); return DynStrTab.getSize(); } @@ -504,8 +547,10 @@ /// Calculates the size of the .shstrtab section. static size_t shStrSize(const ELFStub &Stub) { StringTableBuilder ShStrTab(StringTableBuilder::ELF); + ShStrTab.add(".dynsym"); ShStrTab.add(".dynstr"); ShStrTab.add(".dynamic"); + ShStrTab.add(".def"); ShStrTab.add(".shstrtab"); ShStrTab.finalize(); return ShStrTab.getSize(); @@ -522,30 +567,35 @@ using Elf_Shdr = typename ELFT::Shdr; using Elf_Phdr = typename ELFT::Phdr; using Elf_Dyn = typename ELFT::Dyn; + using Elf_Sym = typename ELFT::Sym; + size_t DefaultAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); // Start with size of ELF header. size_t AlignedSum = sizeof(Elf_Ehdr); // Calculate size of program headers. (PT_LOAD and PT_DYNAMIC) - AlignedSum += sizeof(Elf_Phdr) * 2; + AlignedSum += sizeof(Elf_Phdr) * 3; - // Calculate size of section headers. (SHT_NULL, .dynstr, .dynamic, and - // .shstrtab) - AlignedSum += 4 * sizeof(Elf_Shdr); + // Calculate size of section headers. (SHT_NULL, .dynsym, .dynstr, .dynamic, + // .def, and .shstrtab) + AlignedSum += 6 * sizeof(Elf_Shdr); - // TODO: Calculate size of .dynsym section. + // Calculate size of .dynsym section. + AlignedSum = alignTo(AlignedSum, DefaultAlign); + AlignedSum += sizeof(Elf_Sym) * (Stub.Symbols.size() + 1); // Calculate size of .dynstr. AlignedSum += dynStrSize(Stub); // Calculate size of dynamic section. - size_t DynAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); - AlignedSum = alignTo(AlignedSum, DynAlign); - // DT_STRTAB, DT_STRSZ, and DT_NULL entries. - AlignedSum += 3 * sizeof(Elf_Dyn); + AlignedSum = alignTo(AlignedSum, DefaultAlign); + // DT_STRTAB, DT_STRSZ, DT_SYMTAB, DT_SYMENT, and DT_NULL entries. + AlignedSum += 5 * sizeof(Elf_Dyn); // Other dynamic entries. if (Stub.SoName.hasValue()) AlignedSum += sizeof(Elf_Dyn); AlignedSum += Stub.NeededLibs.size() * sizeof(Elf_Dyn); + // Align for .def. + AlignedSum = alignTo(AlignedSum, 0x1000); // Calculate size of .shstrtab. AlignedSum += shStrSize(Stub); return AlignedSum; @@ -593,9 +643,12 @@ template struct SectionHeaders { typename ELFT::Shdr *NullShdr = nullptr; + typename ELFT::Shdr *DotDynsym = nullptr; typename ELFT::Shdr *DotDynstr = nullptr; typename ELFT::Shdr *DotDynamic = nullptr; typename ELFT::Shdr *DotShstrtab = nullptr; + typename ELFT::Shdr *DotDef = nullptr; + size_t DefIdx = 0; }; /// This initializes required section headers and writes them to a buffer. @@ -623,6 +676,13 @@ ElfHeader.e_shnum += 1; WriteOffset += sizeof(Elf_Shdr); + // Dynsym section. + Shdrs.DotDynsym = reinterpret_cast(Base + WriteOffset); + initDynSymShdr(*Shdrs.DotDynsym); + ShStrTab.add(".dynsym"); + ElfHeader.e_shnum += 1; + WriteOffset += sizeof(Elf_Shdr); + // DynStr section. Shdrs.DotDynstr = reinterpret_cast(Base + WriteOffset); initDynStrShdr(*Shdrs.DotDynstr); @@ -635,11 +695,16 @@ Shdrs.DotDynamic = reinterpret_cast(Base + WriteOffset); initDynamicShdr(*Shdrs.DotDynamic); ShStrTab.add(".dynamic"); - Shdrs.DotDynamic->sh_link = DynStrIdx; ElfHeader.e_shnum += 1; WriteOffset += sizeof(Elf_Shdr); - // TODO: Add SHT_NOBITS .def section. + // Def section. + Shdrs.DotDef = reinterpret_cast(Base + WriteOffset); + initDefShdr(*Shdrs.DotDef); + ShStrTab.add(".def"); + Shdrs.DefIdx = ElfHeader.e_shnum; + ElfHeader.e_shnum += 1; + WriteOffset += sizeof(Elf_Shdr); // ShStrTab section. Shdrs.DotShstrtab = reinterpret_cast(Base + WriteOffset); @@ -653,9 +718,15 @@ // Update SHT null: Shdrs.NullShdr->sh_size = ElfHeader.e_shnum; + + Shdrs.DotDynamic->sh_link = DynStrIdx; + Shdrs.DotDynsym->sh_link = DynStrIdx; + ShStrTab.finalize(); + Shdrs.DotDynsym->sh_name = ShStrTab.getOffset(".dynsym"); Shdrs.DotDynstr->sh_name = ShStrTab.getOffset(".dynstr"); Shdrs.DotDynamic->sh_name = ShStrTab.getOffset(".dynamic"); + Shdrs.DotDef->sh_name = ShStrTab.getOffset(".def"); Shdrs.DotShstrtab->sh_name = ShStrTab.getOffset(".shstrtab"); // Warning sections. @@ -663,6 +734,76 @@ return Shdrs; } +/// This function combines ELFSymbolType with symbol binding to create a st_info +/// member. Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are +/// supported. ELFSymbolType::Unknown symbol types are mapped to STT_NOTYPE. +/// +/// @return st_info created from symbol type and binding. +template +uint8_t convertTypeToInfo(ELFSymbolType Type, uint8_t Binding) { + Binding = Binding << 4; + uint8_t Info = 0; + switch (Type) { + case ELFSymbolType::NoType: + Info = ELF::STT_NOTYPE; + break; + case ELFSymbolType::Object: + Info = ELF::STT_OBJECT; + break; + case ELFSymbolType::Func: + Info = ELF::STT_FUNC; + break; + case ELFSymbolType::TLS: + Info = ELF::STT_TLS; + break; + default: + Info = ELF::STT_NOTYPE; + } + return Info | Binding; +} + +/// This function writes the symbols from an ELFStub to a mutable ArrayRef of +/// dynamic symbols. +/// +/// @param Stub Source ELFStub to pull symbol information from. +/// @param Shdrs Relevant section headers (.def and .dynsym). +/// @param DynStrTab A finalized string table with symbol names already added. +/// @param DynSym The uninitialized mutable ArrayRef of symbols to populate. +template +static void writeSyms(const ELFStub &Stub, + SectionHeaders Shdrs, + StringTableBuilder &DynStrTab, + MutableArrayRef DynSym) { + using Elf_Sym = typename ELFT::Sym; + assert(Stub.Symbols.size() + 1 == DynSym.size() && + "Number of symbols allocated for .dynsym doesn't match the number of " + "symbols in the source"); + // Write a NULL symbol first. + Elf_Sym *SymIterator = DynSym.begin(); + memset(SymIterator, 0, sizeof(Elf_Sym)); + Shdrs.DotDynsym->sh_size += sizeof(Elf_Sym); + + // Write other symbols. + for (const ELFSymbol &Sym : Stub.Symbols) { + ++SymIterator; + SymIterator->st_name = DynStrTab.getOffset(Sym.Name); + uint8_t Binding = Sym.Weak ? STB_WEAK : STB_GLOBAL; + SymIterator->st_info = convertTypeToInfo(Sym.Type, Binding); + SymIterator->st_other = STV_DEFAULT; + SymIterator->st_shndx = Sym.Undefined ? SHN_UNDEF : Shdrs.DefIdx; + SymIterator->st_size = Sym.Size; + + Shdrs.DotDynsym->sh_size += sizeof(Elf_Sym); + + if (!Sym.Undefined) { + // determine offset in the section this symbol is defined in. + SymIterator->st_value = + alignTo(Shdrs.DotDef->sh_size, Shdrs.DotDef->sh_addralign); + Shdrs.DotDef->sh_size = SymIterator->st_value + SymIterator->st_size; + } + } +} + /// This function generates, aligns, and writes the .dynamic section. /// dynamic shared object. /// Offsets, indexes, links, etc. for section and program headers are just @@ -682,6 +823,7 @@ uint8_t *Base, size_t WriteOffset) { using Elf_Dyn = typename ELFT::Dyn; + using Elf_Sym = typename ELFT::Sym; size_t DynAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); std::vector DynEntries; @@ -691,6 +833,18 @@ DynStrTabEnt.d_un.d_ptr = Shdrs.DotDynstr->sh_addr; DynEntries.push_back(DynStrTabEnt); + // Add DT_SYMTAB entry. + Elf_Dyn DynSymTabEnt; + DynSymTabEnt.d_tag = DT_SYMTAB; + DynSymTabEnt.d_un.d_ptr = Shdrs.DotDynsym->sh_addr; + DynEntries.push_back(DynSymTabEnt); + + // Add DT_SYMENT entry. + Elf_Dyn DynSymEntSz; + DynSymEntSz.d_tag = DT_SYMENT; + DynSymEntSz.d_un.d_val = sizeof(Elf_Sym); + DynEntries.push_back(DynSymEntSz); + // Add DT_STRSZ entry. Elf_Dyn DynStrSzEnt; DynStrSzEnt.d_tag = DT_STRSZ; @@ -752,6 +906,7 @@ using Elf_Ehdr = typename ELFT::Ehdr; using Elf_Shdr = typename ELFT::Shdr; using Elf_Phdr = typename ELFT::Phdr; + using Elf_Sym = typename ELFT::Sym; uint8_t *Buf = BufRef.data(); Elf_Ehdr *ElfHeader = reinterpret_cast(Buf); initELFHeader(*ElfHeader, Stub.Arch); @@ -764,6 +919,12 @@ ElfHeader->e_phoff = WriteOffset; ElfHeader->e_phnum += 1; WriteOffset += sizeof(Elf_Phdr); + // PT_LOAD for .def. + Elf_Phdr* PTLoadDefPhdr = reinterpret_cast(Buf + WriteOffset); + initLoadPhdr(*PTLoadDefPhdr); + PTLoadDefPhdr->p_flags |= PF_W; + ElfHeader->e_phnum += 1; + WriteOffset += sizeof(Elf_Phdr); // PT_DYNAMIC for .dynamic. Elf_Phdr* PTDynPhdr = reinterpret_cast(Buf + WriteOffset); initDynamicPhdr(*PTDynPhdr); @@ -784,12 +945,23 @@ for (const std::string &LibName : Stub.NeededLibs) { DynStrTab.add(LibName); } - - // TODO: Add symbol names to .dynstr. + // Add symbol names to .dynstr. + for (const ELFSymbol &Sym : Stub.Symbols) { + DynStrTab.add(Sym.Name); + } DynStrTab.finalize(); - // TODO: Write .dynsym contents. - // TODO: Update size of SHT_NOBITS section. + // Write .dynsym. + size_t SymAlign = ELFT::Is64Bits ? sizeof(uint64_t) : sizeof(uint32_t); + WriteOffset = padAndAlign(Buf, WriteOffset, SymAlign); + // Update offset and address of .dynsym header. + Shdrs.DotDynsym->sh_offset = alignTo(WriteOffset, SymAlign); + Shdrs.DotDynsym->sh_addr = Shdrs.DotDynsym->sh_offset; + // Actually write symbol table. + Elf_Sym *FirstSym = reinterpret_cast(Buf + WriteOffset); + MutableArrayRef DynSyms(FirstSym, Stub.Symbols.size() + 1); + writeSyms(Stub, Shdrs, DynStrTab, DynSyms); + WriteOffset += sizeof(Elf_Sym) * DynSyms.size(); // Write .dynstr contents: DynStrTab.write(Buf + WriteOffset); @@ -803,11 +975,28 @@ writeDynamic(Stub, Shdrs, DynStrTab, Buf, WriteOffset); updatePTDynEntry(*Shdrs.DotDynamic, *PTDynPhdr); - // Mark end of PT_LOAD. + // Mark end of PT_LOAD for dynamic sections. PTLoadDynPhdr->p_filesz = WriteOffset; - // TODO: p_memsz should be WriteOffset + alignment + sizeof(.def). PTLoadDynPhdr->p_memsz = WriteOffset; + // Align for .def section. + size_t Align = 0x1000; + WriteOffset = padAndAlign(Buf, WriteOffset, Align); + + // Populate program header for .def. + Shdrs.DotDef->sh_offset = WriteOffset; + Shdrs.DotDef->sh_addr = alignTo(WriteOffset, 0x1000); + PTLoadDefPhdr->p_offset = WriteOffset; + PTLoadDefPhdr->p_vaddr = Shdrs.DotDef->sh_addr; + PTLoadDefPhdr->p_paddr = Shdrs.DotDef->sh_addr; + PTLoadDefPhdr->p_filesz = 0; + PTLoadDefPhdr->p_memsz = Shdrs.DotDef->sh_size; + // Update .dynsym so the st_value offsets become real addresses. + for (Elf_Sym &Sym : DynSyms.drop_front(1)) { + if (Sym.st_shndx != SHN_UNDEF) + Sym.st_value += PTLoadDefPhdr->p_vaddr; + } + // Write ShStrTab contents: Shdrs.DotShstrtab->sh_offset = WriteOffset; ShStrTab.write(Buf + WriteOffset);