Commit 31f2ad9c authored by Georgii Rymar's avatar Georgii Rymar
Browse files

[yaml2obj] - Automatically assign sh_addr for allocatable sections.

I've noticed that it is not convenient to create YAMLs from
binaries (using obj2yaml) that have to be test cases for obj2yaml
later (after applying yaml2obj).

The problem, for example is that obj2yaml emits "DynamicSymbols:"
key instead of .dynsym. It also does not create .dynstr.
And when a YAML document without explicitly defined .dynsym/.dynstr
is given to yaml2obj, we have issues:

1) These sections are placed after non-allocatable sections (I've fixed it in D74756).
2) They have VA == 0. User needs create descriptions for such sections explicitly manually
    to set a VA.

This patch addresses (2). I suggest to let yaml2obj assign virtual addresses by itself.
It makes an output binary to be much closer to "normal" ELF.
(It is still possible to use "Address: 0x0" for a section to get the original behavior
if it is needed)

Differential revision: https://reviews.llvm.org/D74764
parent 635034f1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ struct Chunk {
struct Section : public Chunk {
  ELF_SHT Type;
  Optional<ELF_SHF> Flags;
  llvm::yaml::Hex64 Address;
  Optional<llvm::yaml::Hex64> Address;
  StringRef Link;
  llvm::yaml::Hex64 AddressAlign;
  Optional<llvm::yaml::Hex64> EntSize;
+34 −4
Original line number Diff line number Diff line
@@ -128,6 +128,7 @@ template <class ELFT> class ELFState {
  NameToIdxMap DynSymN2I;
  ELFYAML::Object &Doc;

  uint64_t LocationCounter = 0;
  bool HasError = false;
  yaml::ErrorHandler ErrHandler;
  void reportError(const Twine &Msg);
@@ -218,6 +219,8 @@ template <class ELFT> class ELFState {

  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 @@ bool ELFState<ELFT>::initImplicitHeader(ContiguousBlobAccumulator &CBA,
  else
    return false;

  LocationCounter += Header.sh_size;

  // Override section fields if requested.
  overrideFields<ELFT>(YAMLSec, Header);
  return true;
@@ -413,6 +418,7 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
  for (const std::unique_ptr<ELFYAML::Chunk> &D : Doc.Chunks) {
    if (auto S = dyn_cast<ELFYAML::Fill>(D.get())) {
      writeFill(*S, CBA);
      LocationCounter += S->Size;
      continue;
    }

@@ -438,9 +444,10 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
    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 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
      llvm_unreachable("Unknown section type");
    }

    LocationCounter += SHeader.sh_size;

    // Override section fields if requested.
    overrideFields<ELFT>(Sec, SHeader);
  }
}

template <class ELFT>
void ELFState<ELFT>::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<ELFYAML::Symbol> Symbols) {
  for (size_t I = 0; I < Symbols.size(); ++I)
    if (Symbols[I].Binding.value != ELF::STB_LOCAL)
@@ -629,7 +659,8 @@ void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader,
                           ? (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 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,

  // 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 <class ELFT> void ELFState<ELFT>::reportError(const Twine &Msg) {
+1 −1
Original line number Diff line number Diff line
@@ -1013,7 +1013,7 @@ static void commonSectionMapping(IO &IO, ELFYAML::Section &Section) {
  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);
+3 −3
Original line number Diff line number Diff line
@@ -193,9 +193,9 @@ ProgramHeaders:

# 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
+4 −4
Original line number Diff line number Diff line
@@ -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 @@ DynamicSymbols:
# 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 (<corrupt>)
# 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: <corrupt vn_file: 9>  Cnt: 1
# GNU-NOLINK-NEXT:   0x0010:   Name: <corrupt>  Flags: none Version: 2

@@ -231,7 +231,7 @@ DynamicSymbols: []
# 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: <corrupt vn_file: 1>  Cnt: 1
# GNU-OFFSET-EQ-NEXT:   0x0010:   Name: <corrupt>  Flags: none  Version: 0

@@ -562,7 +562,7 @@ DynamicSymbols:
# 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

Loading