Index: test/tools/yaml2obj/implicit-sections.test =================================================================== --- /dev/null +++ test/tools/yaml2obj/implicit-sections.test @@ -0,0 +1,86 @@ +## Check the section header properties of ".dynsym", +## ".dynstr", ".symtab", ".strtab", ".shstrtab". +## These sections sections are usually added implicitly, +## but here we add them explicitly in YAML and verify. +## We check their order matches YAML and that file offset is +## ascending. This is a natural default behavior. + +# RUN: yaml2obj --docnum=1 %s -o %t1 +# RUN: llvm-readelf -S %t1 | FileCheck %s + +# CHECK: Section Headers: +# CHECK-NEXT: [Nr] Name Type Address Off Size +# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# CHECK-NEXT: [ 1] .dynstr STRTAB 0000000000000100 000200 000009 +# CHECK-NEXT: [ 2] .dynsym DYNSYM 0000000000000150 000209 000030 +# CHECK-NEXT: [ 3] .symtab SYMTAB 0000000000000000 000239 000018 +# CHECK-NEXT: [ 4] .strtab STRTAB 0000000000000000 000251 000001 +# CHECK-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 000252 000035 +# CHECK-NEXT: [ 6] .text.foo PROGBITS 0000000000000200 000287 000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Address: 0x100 + - Name: .dynsym + Type: SHT_DYNSYM + Address: 0x150 + - Name: .symtab + Type: SHT_SYMTAB + - Name: .strtab + Type: SHT_STRTAB + - Name: .shstrtab + Type: SHT_STRTAB + - Name: .text.foo + Type: SHT_PROGBITS + Address: 0x200 +## Symbol is required for the .dynsym to be generated. +DynamicSymbols: + - Name: _Z3fooi + Binding: STB_GLOBAL + +## Check that yaml2obj creates empty .dynstr and .dynsym sections for +## the case when no dynamic symbols were specified and Content wasn't set, +## but the sections were explicitly listed. Check their VAs are correct. + +# RUN: yaml2obj --docnum=2 %s -o %t2 +# RUN: llvm-readelf -S %t2 | FileCheck %s --check-prefix=NODYNSYM + +# NODYNSYM: Section Headers: +# NODYNSYM-NEXT: [Nr] Name Type Address Off Size +# NODYNSYM-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# NODYNSYM-NEXT: [ 1] .dynstr STRTAB 0000000000000100 000200 000001 +# NODYNSYM-NEXT: [ 2] .dynsym DYNSYM 0000000000000150 000201 000018 +# NODYNSYM-NEXT: [ 3] .symtab SYMTAB 0000000000000000 000219 000018 +# NODYNSYM-NEXT: [ 4] .strtab STRTAB 0000000000000000 000231 000001 +# NODYNSYM-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 000232 000035 +# NODYNSYM-NEXT: [ 6] .text.foo PROGBITS 0000000000000200 000267 000000 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + Machine: EM_X86_64 +Sections: + - Name: .dynstr + Type: SHT_STRTAB + Address: 0x100 + - Name: .dynsym + Type: SHT_DYNSYM + Address: 0x150 + - Name: .symtab + Type: SHT_SYMTAB + - Name: .strtab + Type: SHT_STRTAB + - Name: .shstrtab + Type: SHT_STRTAB + - Name: .text.foo + Type: SHT_PROGBITS + Address: 0x200 Index: tools/yaml2obj/yaml2elf.cpp =================================================================== --- tools/yaml2obj/yaml2elf.cpp +++ tools/yaml2obj/yaml2elf.cpp @@ -136,13 +136,19 @@ bool buildSymbolIndex(ArrayRef Symbols); void initELFHeader(Elf_Ehdr &Header); void initProgramHeaders(std::vector &PHeaders); - bool initSectionHeaders(std::vector &SHeaders, + bool initImplicitHeader(ELFState &State, ContiguousBlobAccumulator &CBA, + Elf_Shdr &Header, StringRef SecName, + ELFYAML::Section *YAMLSec); + bool initSectionHeaders(ELFState &State, + std::vector &SHeaders, ContiguousBlobAccumulator &CBA); void initSymtabSectionHeader(Elf_Shdr &SHeader, SymtabType STType, - ContiguousBlobAccumulator &CBA); + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec); void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, - ContiguousBlobAccumulator &CBA); + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec); void setProgramHeaderLayout(std::vector &PHeaders, std::vector &SHeaders); void addSymbols(ArrayRef Symbols, std::vector &Syms, @@ -248,7 +254,36 @@ } template -bool ELFState::initSectionHeaders(std::vector &SHeaders, +bool ELFState::initImplicitHeader(ELFState &State, + ContiguousBlobAccumulator &CBA, + Elf_Shdr &Header, StringRef SecName, + ELFYAML::Section *YAMLSec) { + // Check if the header was already initialized. + if (Header.sh_offset) + return false; + + if (SecName == ".symtab") + State.initSymtabSectionHeader(Header, SymtabType::Static, CBA, YAMLSec); + else if (SecName == ".strtab") + State.initStrtabSectionHeader(Header, SecName, State.DotStrtab, CBA, + YAMLSec); + else if (SecName == ".shstrtab") + State.initStrtabSectionHeader(Header, SecName, State.DotShStrtab, CBA, + YAMLSec); + + else if (SecName == ".dynsym") + State.initSymtabSectionHeader(Header, SymtabType::Dynamic, CBA, YAMLSec); + else if (SecName == ".dynstr") + State.initStrtabSectionHeader(Header, SecName, State.DotDynstr, CBA, + YAMLSec); + else + return false; + return true; +} + +template +bool ELFState::initSectionHeaders(ELFState &State, + std::vector &SHeaders, ContiguousBlobAccumulator &CBA) { // Ensure SHN_UNDEF entry is present. An all-zero section header is a // valid SHN_UNDEF entry since SHT_NULL == 0. @@ -271,6 +306,15 @@ SHeader.sh_link = Index; } + // We have a few sections like string or symbol tables that are added + // implicitly later. However, if they are explicitly specified in the YAML, + // we want to write them right now. This ensures the file offset remains + // correct. + if (initImplicitHeader(State, CBA, SHeader, Sec->Name, Sec.get())) { + SHeaders.push_back(SHeader); + continue; + } + if (auto S = dyn_cast(Sec.get())) { if (!writeSectionContent(SHeader, *S, CBA)) return false; @@ -306,6 +350,26 @@ SHeaders.push_back(SHeader); } + + // Populate SHeaders with implicit sections not present in the Doc. + for (StringRef Name : State.implicitSectionNames()) + if (State.SN2I.get(Name) >= SHeaders.size()) + SHeaders.push_back({}); + + // Initialize the implicit sections. + initImplicitHeader(State, CBA, SHeaders[State.SN2I.get(".symtab")], ".symtab", + nullptr /*DocSec*/); + initImplicitHeader(State, CBA, SHeaders[State.SN2I.get(".strtab")], ".strtab", + nullptr /*DocSec*/); + initImplicitHeader(State, CBA, SHeaders[State.SN2I.get(".shstrtab")], + ".shstrtab", nullptr /*DocSec*/); + if (!Doc.DynamicSymbols.empty()) { + initImplicitHeader(State, CBA, SHeaders[State.SN2I.get(".dynsym")], + ".dynsym", nullptr /*DocSec*/); + initImplicitHeader(State, CBA, SHeaders[State.SN2I.get(".dynstr")], + ".dynstr", nullptr /*DocSec*/); + } + return true; } @@ -319,7 +383,8 @@ template void ELFState::initSymtabSectionHeader(Elf_Shdr &SHeader, SymtabType STType, - ContiguousBlobAccumulator &CBA) { + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec) { zero(SHeader); bool IsStatic = STType == SymtabType::Static; SHeader.sh_name = DotShStrtab.getOffset(IsStatic ? ".symtab" : ".dynsym"); @@ -330,57 +395,71 @@ // One greater than symbol table index of the last local symbol. const auto &Symbols = IsStatic ? Doc.Symbols : Doc.DynamicSymbols; - SHeader.sh_info = findFirstNonGlobal(Symbols) + 1; - SHeader.sh_entsize = sizeof(Elf_Sym); - SHeader.sh_addralign = 8; - // Get the section index ignoring the SHT_NULL section. - unsigned SecNdx = - IsStatic ? getDotSymTabSecNo() - 1 : getDotDynSymSecNo() - 1; // If the symbol table section is explicitly described in the YAML // then we should set the fields requested. - if (SecNdx < Doc.Sections.size()) { - ELFYAML::Section *Sec = Doc.Sections[SecNdx].get(); - SHeader.sh_addr = Sec->Address; - if (auto S = dyn_cast(Sec)) - SHeader.sh_info = S->Info; - } - - std::vector Syms; - { - // Ensure STN_UNDEF is present - Elf_Sym Sym; - zero(Sym); - Syms.push_back(Sym); - } + ELFYAML::RawContentSection *RawSec = + dyn_cast_or_null(YAMLSec); + SHeader.sh_info = + RawSec ? (unsigned)RawSec->Info : findFirstNonGlobal(Symbols) + 1; + SHeader.sh_entsize = (YAMLSec && YAMLSec->EntSize) + ? (uint64_t)(*YAMLSec->EntSize) + : sizeof(Elf_Sym); + SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 8; + SHeader.sh_addr = YAMLSec ? (uint64_t)YAMLSec->Address : 0; + + if (RawSec && RawSec->Content.binary_size()) { + RawSec->Content.writeAsBinary( + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign)); + SHeader.sh_size = RawSec->Size; + } else { + std::vector Syms; + { + // Ensure STN_UNDEF is present + Elf_Sym Sym; + zero(Sym); + Syms.push_back(Sym); + } - addSymbols(Symbols, Syms, IsStatic ? DotStrtab : DotDynstr); + addSymbols(Symbols, Syms, IsStatic ? DotStrtab : DotDynstr); - writeArrayData( - CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign), - makeArrayRef(Syms)); - SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); + writeArrayData( + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign), + makeArrayRef(Syms)); + SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); + } } template void ELFState::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name, StringTableBuilder &STB, - ContiguousBlobAccumulator &CBA) { + ContiguousBlobAccumulator &CBA, + ELFYAML::Section *YAMLSec) { zero(SHeader); SHeader.sh_name = DotShStrtab.getOffset(Name); SHeader.sh_type = ELF::SHT_STRTAB; - STB.write(CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign)); - SHeader.sh_size = STB.getSize(); - SHeader.sh_addralign = 1; + SHeader.sh_addralign = YAMLSec ? (uint64_t)YAMLSec->AddressAlign : 1; + + ELFYAML::RawContentSection *RawSec = + dyn_cast_or_null(YAMLSec); + if (RawSec && RawSec->Content.binary_size()) { + RawSec->Content.writeAsBinary( + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign)); + SHeader.sh_size = RawSec->Size; + } else { + STB.write( + CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign)); + SHeader.sh_size = STB.getSize(); + } + + if (YAMLSec && YAMLSec->EntSize) + SHeader.sh_entsize = *YAMLSec->EntSize; // If .dynstr section is explicitly described in the YAML // then we want to use its section address. if (Name == ".dynstr") { - // Take section index and ignore the SHT_NULL section. - unsigned SecNdx = getDotDynStrSecNo() - 1; - if (SecNdx < Doc.Sections.size()) - SHeader.sh_addr = Doc.Sections[SecNdx]->Address; - + if (YAMLSec) + SHeader.sh_addr = YAMLSec->Address; // We assume that .dynstr is always allocatable. SHeader.sh_flags |= ELF::SHF_ALLOC; } @@ -841,9 +920,6 @@ DotStrtab.add(Sym.Name); DotStrtab.finalize(); - if (Doc.DynamicSymbols.empty()) - return; - // Add the dynamic symbol names to .dynstr section. for (const ELFYAML::Symbol &Sym : Doc.DynamicSymbols) DotDynstr.add(Sym.Name); @@ -898,28 +974,9 @@ ContiguousBlobAccumulator CBA(SectionContentBeginOffset); std::vector SHeaders; - if (!State.initSectionHeaders(SHeaders, CBA)) + if (!State.initSectionHeaders(State, SHeaders, CBA)) return 1; - // Populate SHeaders with implicit sections not present in the Doc - for (StringRef Name : State.implicitSectionNames()) - if (State.SN2I.get(Name) >= SHeaders.size()) - SHeaders.push_back({}); - - // Initialize the implicit sections - State.initSymtabSectionHeader(SHeaders[State.SN2I.get(".symtab")], - SymtabType::Static, CBA); - State.initStrtabSectionHeader(SHeaders[State.SN2I.get(".strtab")], ".strtab", - State.DotStrtab, CBA); - State.initStrtabSectionHeader(SHeaders[State.SN2I.get(".shstrtab")], - ".shstrtab", State.DotShStrtab, CBA); - if (!Doc.DynamicSymbols.empty()) { - State.initSymtabSectionHeader(SHeaders[State.SN2I.get(".dynsym")], - SymtabType::Dynamic, CBA); - State.initStrtabSectionHeader(SHeaders[State.SN2I.get(".dynstr")], - ".dynstr", State.DotDynstr, CBA); - } - // Now we can decide segment offsets State.setProgramHeaderLayout(PHeaders, SHeaders);