Index: llvm/include/llvm/ObjectYAML/ELFYAML.h =================================================================== --- llvm/include/llvm/ObjectYAML/ELFYAML.h +++ 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; Index: llvm/lib/ObjectYAML/ELFEmitter.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFEmitter.cpp +++ 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,30 @@ 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; + } + + if (!(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 +655,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 +705,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) { Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ 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); Index: llvm/test/tools/yaml2obj/ELF/section-address-assign.yaml =================================================================== --- /dev/null +++ llvm/test/tools/yaml2obj/ELF/section-address-assign.yaml @@ -0,0 +1,72 @@ +## This test shows how yaml2obj automatically assigns virtual addresses for sections. + +# RUN: yaml2obj %s -o %t +# RUN: llvm-readelf --sections %t | FileCheck %s + +# CHECK: Section Headers: +# CHECK-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al +# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 +# CHECK-NEXT: [ 1] .text.any.addr PROGBITS 0000000000001000 000040 000003 00 A 0 0 0 +# CHECK-NEXT: [ 2] .text.shsize PROGBITS 0000000000001003 000043 001234 00 A 0 0 0 +# CHECK-NEXT: [ 3] .text.align PROGBITS 0000000000001100 000100 000004 00 A 0 0 256 +# CHECK-NEXT: [ 4] .data.any.addr PROGBITS 0000000000002000 000104 000001 00 A 0 0 0 +# CHECK-NEXT: [ 5] .data.after.fill PROGBITS 0000000000002101 000205 000001 00 A 0 0 0 +# CHECK-NEXT: [ 6] .data.return.back PROGBITS 0000000000001500 000206 000001 00 A 0 0 0 +# CHECK-NEXT: [ 7] .data.return.back.foo PROGBITS 0000000000001501 000207 000000 00 A 0 0 0 +# CHECK-NEXT: [ 8] .dynsym DYNSYM 0000000000001508 000208 000018 18 A 9 1 8 +# CHECK-NEXT: [ 9] .dynstr STRTAB 0000000000001520 000220 000001 00 A 0 0 1 +# CHECK-NEXT: [10] .strtab STRTAB 0000000000000000 000221 000001 00 0 0 1 +# CHECK-NEXT: [11] .shstrtab STRTAB 0000000000000000 000222 000093 00 0 0 1 + +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_DYN + 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: [] Index: llvm/tools/obj2yaml/elf2yaml.cpp =================================================================== --- llvm/tools/obj2yaml/elf2yaml.cpp +++ llvm/tools/obj2yaml/elf2yaml.cpp @@ -502,7 +502,7 @@ S.Type = Shdr->sh_type; if (Shdr->sh_flags) S.Flags = static_cast(Shdr->sh_flags); - S.Address = 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);