diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h --- a/llvm/include/llvm/ObjectYAML/ELFYAML.h +++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h @@ -167,7 +167,7 @@ struct Section : public Chunk { ELF_SHT Type; Optional Flags; - llvm::yaml::Hex64 Address; + Optional Address; StringRef Link; llvm::yaml::Hex64 AddressAlign; Optional EntSize; diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp --- a/llvm/lib/ObjectYAML/ELFEmitter.cpp +++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp @@ -128,6 +128,7 @@ NameToIdxMap DynSymN2I; ELFYAML::Object &Doc; + uint64_t LocationCounter = 0; bool HasError = false; yaml::ErrorHandler ErrHandler; void reportError(const Twine &Msg); @@ -218,6 +219,8 @@ ELFState(ELFYAML::Object &D, yaml::ErrorHandler EH); + void assignSectionAddress(Elf_Shdr &SHeader, ELFYAML::Section *YAMLSec); + public: static bool writeELF(raw_ostream &OS, ELFYAML::Object &Doc, yaml::ErrorHandler EH); @@ -390,6 +393,8 @@ else return false; + LocationCounter += Header.sh_size; + // Override section fields if requested. overrideFields(YAMLSec, Header); return true; @@ -413,6 +418,7 @@ for (const std::unique_ptr &D : Doc.Chunks) { if (auto S = dyn_cast(D.get())) { writeFill(*S, CBA); + LocationCounter += S->Size; continue; } @@ -438,9 +444,10 @@ SHeader.sh_type = Sec->Type; if (Sec->Flags) SHeader.sh_flags = *Sec->Flags; - SHeader.sh_addr = Sec->Address; SHeader.sh_addralign = Sec->AddressAlign; + assignSectionAddress(SHeader, Sec); + if (!Sec->Link.empty()) SHeader.sh_link = toSectionIndex(Sec->Link, Sec->Name); @@ -500,11 +507,34 @@ llvm_unreachable("Unknown section type"); } + LocationCounter += SHeader.sh_size; + // Override section fields if requested. overrideFields(Sec, SHeader); } } +template +void ELFState::assignSectionAddress(Elf_Shdr &SHeader, + ELFYAML::Section *YAMLSec) { + if (YAMLSec && YAMLSec->Address) { + SHeader.sh_addr = *YAMLSec->Address; + LocationCounter = *YAMLSec->Address; + return; + } + + // sh_addr represents the address in the memory image of a process. Sections + // in a relocatable object file or non-allocatable sections do not need + // sh_addr assignment. + if (Doc.Header.Type.value == ELF::ET_REL || + !(SHeader.sh_flags & ELF::SHF_ALLOC)) + return; + + LocationCounter = + alignTo(LocationCounter, SHeader.sh_addralign ? SHeader.sh_addralign : 1); + SHeader.sh_addr = LocationCounter; +} + static size_t findFirstNonGlobal(ArrayRef Symbols) { for (size_t I = 0; I < Symbols.size(); ++I) if (Symbols[I].Binding.value != ELF::STB_LOCAL) @@ -629,7 +659,8 @@ ? (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; + + assignSectionAddress(SHeader, YAMLSec); auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign); if (RawSec && (RawSec->Content || RawSec->Size)) { @@ -678,8 +709,7 @@ // If the section is explicitly described in the YAML // then we want to use its section address. - if (YAMLSec) - SHeader.sh_addr = YAMLSec->Address; + assignSectionAddress(SHeader, YAMLSec); } template void ELFState::reportError(const Twine &Msg) { diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp --- a/llvm/lib/ObjectYAML/ELFYAML.cpp +++ b/llvm/lib/ObjectYAML/ELFYAML.cpp @@ -1013,7 +1013,7 @@ IO.mapOptional("Name", Section.Name, StringRef()); IO.mapRequired("Type", Section.Type); IO.mapOptional("Flags", Section.Flags); - IO.mapOptional("Address", Section.Address, Hex64(0)); + IO.mapOptional("Address", Section.Address); IO.mapOptional("Link", Section.Link, StringRef()); IO.mapOptional("AddressAlign", Section.AddressAlign, Hex64(0)); IO.mapOptional("EntSize", Section.EntSize); diff --git a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test --- a/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test +++ b/llvm/test/tools/llvm-objcopy/ELF/only-keep-debug.test @@ -193,9 +193,9 @@ # CHECK3: [Nr] Name Type Address Off Size ES Flg Lk Inf Al # CHECK3: [ 1] .dynsym NOBITS 0000000000000000 000040 000018 18 A 2 1 1024 -# CHECK3-NEXT: [ 2] .dynstr NOBITS 0000000000000000 000040 000001 00 A 0 0 0 -# CHECK3-NEXT: [ 3] .symtab NOBITS 0000000000000000 000040 000018 18 A 4 1 0 -# CHECK3-NEXT: [ 4] .strtab NOBITS 0000000000000000 000040 000001 00 A 0 0 0 +# CHECK3-NEXT: [ 2] .dynstr NOBITS 0000000000000018 000040 000001 00 A 0 0 0 +# CHECK3-NEXT: [ 3] .symtab NOBITS 0000000000000019 000040 000018 18 A 4 1 0 +# CHECK3-NEXT: [ 4] .strtab NOBITS 0000000000000031 000040 000001 00 A 0 0 0 # CHECK3-NEXT: [ 5] .shstrtab STRTAB 0000000000000000 000040 00002b 00 0 0 1 --- !ELF diff --git a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test --- a/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test +++ b/llvm/test/tools/llvm-readobj/ELF/verneed-invalid.test @@ -13,7 +13,7 @@ # GNU-VERNEED-NAME-NEXT: 000: 0 (*local*) 2 () # GNU-VERNEED-NAME: Version needs section '.gnu.version_r' contains 1 entries: -# GNU-VERNEED-NAME-NEXT: Addr: 0000000000000000 Offset: 0x000044 Link: 4 (.dynstr) +# GNU-VERNEED-NAME-NEXT: Addr: 0000000000200214 Offset: 0x000044 Link: 4 (.dynstr) # GNU-VERNEED-NAME-NEXT: 0x0000: Version: 1 File: somefile Cnt: 1 # GNU-VERNEED-NAME-NEXT: 0x0010: Name: Flags: none Version: 2 @@ -89,7 +89,7 @@ # GNU-NOLINK-NEXT: warning: '[[FILE]]': invalid string table linked to SHT_GNU_verneed section with index 2: invalid sh_type for string table section [index 0]: expected SHT_STRTAB, but got SHT_NULL # GNU-NOLINK-NEXT: 000: 0 (*local*) 2 () # GNU-NOLINK: Version needs section '.gnu.version_r' contains 1 entries: -# GNU-NOLINK-NEXT: Addr: 0000000000000000 Offset: 0x000044 Link: 0 () +# GNU-NOLINK-NEXT: Addr: 0000000000000004 Offset: 0x000044 Link: 0 () # GNU-NOLINK-NEXT: 0x0000: Version: 1 File: Cnt: 1 # GNU-NOLINK-NEXT: 0x0010: Name: Flags: none Version: 2 @@ -231,7 +231,7 @@ # LLVM-OFFSET-EQ-NEXT: ] # GNU-OFFSET-EQ: Version needs section '.gnu.version_r' contains 1 entries: -# GNU-OFFSET-EQ-NEXT: Addr: 0000000000000000 Offset: 0x000044 Link: 1 (.mystrtab) +# GNU-OFFSET-EQ-NEXT: Addr: 0000000000000004 Offset: 0x000044 Link: 1 (.mystrtab) # GNU-OFFSET-EQ-NEXT: 0x0000: Version: 1 File: Cnt: 1 # GNU-OFFSET-EQ-NEXT: 0x0010: Name: Flags: none Version: 0 @@ -562,7 +562,7 @@ # GNU-CUSTOM-DYNSTR-NEXT: Addr: 0000000000000000 Offset: 0x000040 Link: 4 (.dynsym) # GNU-CUSTOM-DYNSTR-NEXT: 000: 0 (*local*) 2 (bcdefghij) # GNU-CUSTOM-DYNSTR: Version needs section '.gnu.version_r' contains 1 entries: -# GNU-CUSTOM-DYNSTR-NEXT: Addr: 0000000000000000 Offset: 0x000044 Link: 3 (.custom.dynstr) +# GNU-CUSTOM-DYNSTR-NEXT: Addr: 0000000000000004 Offset: 0x000044 Link: 3 (.custom.dynstr) # GNU-CUSTOM-DYNSTR-NEXT: 0x0000: Version: 1 File: j Cnt: 1 # GNU-CUSTOM-DYNSTR-NEXT: 0x0010: Name: bcdefghij Flags: none Version: 2 diff --git a/llvm/test/tools/llvm-readobj/ELF/versioninfo.test b/llvm/test/tools/llvm-readobj/ELF/versioninfo.test --- a/llvm/test/tools/llvm-readobj/ELF/versioninfo.test +++ b/llvm/test/tools/llvm-readobj/ELF/versioninfo.test @@ -275,7 +275,7 @@ # GNU-NEXT: 004: 5 (v2) 6 (v3) # GNU-EMPTY: # GNU-NEXT: Version definition section '.gnu.version_d' contains 6 entries: -# GNU-NEXT: Addr: 0000000000000000 Offset: 0x00004c Link: 5 (.dynstr) +# GNU-NEXT: Addr: 000000000000000c Offset: 0x00004c Link: 5 (.dynstr) # GNU-NEXT: 0x0000: Rev: 1 Flags: none Index: 0 Cnt: 1 Name: VERSION1 # GNU-NEXT: 0x001c: Rev: 1 Flags: BASE Index: 0 Cnt: 1 Name: VERSION1 # GNU-NEXT: 0x0038: Rev: 1 Flags: WEAK Index: 0 Cnt: 1 Name: VERSION1 @@ -286,7 +286,7 @@ # GNU-NEXT: 0x00b0: Parent 2: VERSION3 # GNU-EMPTY: # GNU-NEXT: Version needs section '.gnu.version_r' contains 2 entries: -# GNU-NEXT: Addr: 0000000000000000 Offset: 0x000104 Link: 5 (.dynstr) +# GNU-NEXT: Addr: 00000000000000c4 Offset: 0x000104 Link: 5 (.dynstr) # GNU-NEXT: 0x0000: Version: 1 File: verneed1.so.0 Cnt: 5 # GNU-NEXT: 0x0010: Name: v1 Flags: BASE Version: 0 # GNU-NEXT: 0x0020: Name: v1 Flags: WEAK Version: 0 diff --git a/llvm/test/tools/obj2yaml/elf-gnu-hash-section.yaml b/llvm/test/tools/obj2yaml/elf-gnu-hash-section.yaml --- a/llvm/test/tools/obj2yaml/elf-gnu-hash-section.yaml +++ b/llvm/test/tools/obj2yaml/elf-gnu-hash-section.yaml @@ -45,6 +45,7 @@ # INVALID-NEXT: - Name: .gnu.hash.empty # INVALID-NEXT: Type: SHT_GNU_HASH # INVALID-NEXT: Flags: [ SHF_ALLOC ] +# INVALID-NEXT: Address: 0x000000000000000F # INVALID-NEXT: Header: # INVALID-NEXT: SymNdx: 0x00000000 # INVALID-NEXT: Shift2: 0x00000000 diff --git a/llvm/test/tools/yaml2obj/ELF/section-address-assign.yaml b/llvm/test/tools/yaml2obj/ELF/section-address-assign.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/ELF/section-address-assign.yaml @@ -0,0 +1,98 @@ +## Test that yaml2obj automatically assigns sh_addr to allocatable sections for ET_EXEC/ET_DYN files. + +# RUN: yaml2obj %s -o %t.so -D TYPE=ET_DYN +# RUN: llvm-readelf --sections %t.so | FileCheck %s --check-prefix=EXE-DSO + +# RUN: yaml2obj %s -o %t -D TYPE=ET_EXEC +# RUN: llvm-readelf --sections %t | FileCheck %s --check-prefix=EXE-DSO + +# RUN: yaml2obj %s -o %t.o -D TYPE=ET_REL +# RUN: llvm-readelf --sections %t.o | FileCheck %s --check-prefix=REL + +## We assign virtual addresses to allocatable sections automatically for executables and shared libraries. + +# EXE-DSO: Section Headers: +# EXE-DSO-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# EXE-DSO-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# EXE-DSO-NEXT: [ 1] .text.any.addr PROGBITS 0000000000001000 000040 000003 00 A 0 0 0 +# EXE-DSO-NEXT: [ 2] .text.shsize PROGBITS 0000000000001003 000043 001234 00 A 0 0 0 +# EXE-DSO-NEXT: [ 3] .text.align PROGBITS 0000000000001100 000100 000004 00 A 0 0 256 +# EXE-DSO-NEXT: [ 4] .data.any.addr PROGBITS 0000000000002000 000104 000001 00 A 0 0 0 +# EXE-DSO-NEXT: [ 5] .data.after.fill PROGBITS 0000000000002101 000205 000001 00 A 0 0 0 +# EXE-DSO-NEXT: [ 6] .data.return.back PROGBITS 0000000000001500 000206 000001 00 A 0 0 0 +# EXE-DSO-NEXT: [ 7] .data.return.back.foo PROGBITS 0000000000001501 000207 000000 00 A 0 0 0 +# EXE-DSO-NEXT: [ 8] .dynsym DYNSYM 0000000000001508 000208 000018 18 A 9 1 8 +# EXE-DSO-NEXT: [ 9] .dynstr STRTAB 0000000000001520 000220 000001 00 A 0 0 1 +# EXE-DSO-NEXT: [10] .strtab STRTAB 0000000000000000 000221 000001 00 0 0 1 +# EXE-DSO-NEXT: [11] .shstrtab STRTAB 0000000000000000 000222 000093 00 0 0 1 + +## We do not assign virtual addresses to allocatable sections in a relocatable object +## unless YAML document has an explicit request. + +# REL: Section Headers: +# REL-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# REL-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# REL-NEXT: [ 1] .text.any.addr PROGBITS 0000000000001000 000040 000003 00 A 0 0 0 +# REL-NEXT: [ 2] .text.shsize PROGBITS 0000000000000000 000043 001234 00 A 0 0 0 +# REL-NEXT: [ 3] .text.align PROGBITS 0000000000000000 000100 000004 00 A 0 0 256 +# REL-NEXT: [ 4] .data.any.addr PROGBITS 0000000000002000 000104 000001 00 A 0 0 0 +# REL-NEXT: [ 5] .data.after.fill PROGBITS 0000000000000000 000205 000001 00 A 0 0 0 +# REL-NEXT: [ 6] .data.return.back PROGBITS 0000000000001500 000206 000001 00 A 0 0 0 +# REL-NEXT: [ 7] .data.return.back.foo PROGBITS 0000000000000000 000207 000000 00 A 0 0 0 +# REL-NEXT: [ 8] .dynsym DYNSYM 0000000000000000 000208 000018 18 A 9 1 8 +# REL-NEXT: [ 9] .dynstr STRTAB 0000000000000000 000220 000001 00 A 0 0 1 +# REL-NEXT: [10] .strtab STRTAB 0000000000000000 000221 000001 00 0 0 1 +# REL-NEXT: [11] .shstrtab STRTAB 0000000000000000 000222 000093 00 0 0 1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: [[TYPE]] + Machine: EM_X86_64 +Sections: +## Show we can place a section at any address. + - Name: .text.any.addr + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x1000 + Size: 0x3 +## Test that ShSize does not affect virtual addresses. + - Name: .text.shsize + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + ShSize: 0x1234 +## Show we respect an address align when automatically +## assign virtual addresses. + - Name: .text.align + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + AddressAlign: 0x100 + Size: 0x4 +## We can set another address for a subsequent section. + - Name: .data.any.addr + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Address: 0x2000 + Size: 0x1 +## Show that Fill occupies VA space. + - Type: Fill + Pattern: "AABB" + Size: 0x100 + - Name: .data.after.fill + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Size: 0x1 +## Show we can return back in the address space and +## continue placing sections. The order of sections in the +## section header table will match the order in the YAML description. + - Name: .data.return.back + Address: 0x1500 + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] + Size: 0x1 + - Name: .data.return.back.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC ] +## Used to trigger creation of .dynsym and .dynstr. +DynamicSymbols: [] diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp --- a/llvm/tools/obj2yaml/elf2yaml.cpp +++ b/llvm/tools/obj2yaml/elf2yaml.cpp @@ -502,7 +502,8 @@ S.Type = Shdr->sh_type; if (Shdr->sh_flags) S.Flags = static_cast(Shdr->sh_flags); - S.Address = Shdr->sh_addr; + if (Shdr->sh_addr) + S.Address = static_cast(Shdr->sh_addr); S.AddressAlign = Shdr->sh_addralign; if (Shdr->sh_entsize) S.EntSize = static_cast(Shdr->sh_entsize);