Commit dd101539 authored by Georgii Rymar's avatar Georgii Rymar
Browse files

[yaml2obj/obj2yaml] - Add support for SHT_LLVM_LINKER_OPTIONS sections.

SHT_LLVM_LINKER_OPTIONS section contains pairs of null-terminated strings.
This patch adds support for them.

Differential revision: https://reviews.llvm.org/D69895
parent 88b04ef8
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -147,7 +147,8 @@ struct Chunk {
    Symver,
    MipsABIFlags,
    Addrsig,
    Fill
    Fill,
    LinkerOptions,
  };

  ChunkKind Kind;
@@ -349,6 +350,22 @@ struct AddrsigSection : Section {
  static bool classof(const Chunk *S) { return S->Kind == ChunkKind::Addrsig; }
};

struct LinkerOption {
  StringRef Key;
  StringRef Value;
};

struct LinkerOptionsSection : Section {
  Optional<std::vector<LinkerOption>> Options;
  Optional<yaml::BinaryRef> Content;

  LinkerOptionsSection() : Section(ChunkKind::LinkerOptions) {}

  static bool classof(const Chunk *S) {
    return S->Kind == ChunkKind::LinkerOptions;
  }
};

struct SymverSection : Section {
  std::vector<uint16_t> Entries;

@@ -464,6 +481,7 @@ struct Object {
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::AddrsigSymbol)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::StackSizeEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::DynamicEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::LinkerOption)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::NoteEntry)
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Chunk>)
@@ -631,6 +649,10 @@ template <> struct MappingTraits<ELFYAML::AddrsigSymbol> {
  static void mapping(IO &IO, ELFYAML::AddrsigSymbol &Sym);
};

template <> struct MappingTraits<ELFYAML::LinkerOption> {
  static void mapping(IO &IO, ELFYAML::LinkerOption &Sym);
};

template <> struct MappingTraits<ELFYAML::Relocation> {
  static void mapping(IO &IO, ELFYAML::Relocation &Rel);
};
+29 −0
Original line number Diff line number Diff line
@@ -200,6 +200,9 @@ template <class ELFT> class ELFState {
  void writeSectionContent(Elf_Shdr &SHeader,
                           const ELFYAML::GnuHashSection &Section,
                           ContiguousBlobAccumulator &CBA);
  void writeSectionContent(Elf_Shdr &SHeader,
                           const ELFYAML::LinkerOptionsSection &Section,
                           ContiguousBlobAccumulator &CBA);

  void writeFill(ELFYAML::Fill &Fill, ContiguousBlobAccumulator &CBA);

@@ -466,6 +469,8 @@ void ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
      writeSectionContent(SHeader, *S, CBA);
    } else if (auto S = dyn_cast<ELFYAML::AddrsigSection>(Sec)) {
      writeSectionContent(SHeader, *S, CBA);
    } else if (auto S = dyn_cast<ELFYAML::LinkerOptionsSection>(Sec)) {
      writeSectionContent(SHeader, *S, CBA);
    } else if (auto S = dyn_cast<ELFYAML::NoteSection>(Sec)) {
      writeSectionContent(SHeader, *S, CBA);
    } else if (auto S = dyn_cast<ELFYAML::GnuHashSection>(Sec)) {
@@ -892,6 +897,30 @@ void ELFState<ELFT>::writeSectionContent(
  }
}

template <class ELFT>
void ELFState<ELFT>::writeSectionContent(
    Elf_Shdr &SHeader, const ELFYAML::LinkerOptionsSection &Section,
    ContiguousBlobAccumulator &CBA) {
  raw_ostream &OS =
      CBA.getOSAndAlignedOffset(SHeader.sh_offset, SHeader.sh_addralign);

  if (Section.Content) {
    SHeader.sh_size = writeContent(OS, Section.Content, None);
    return;
  }

  if (!Section.Options)
    return;

  for (const ELFYAML::LinkerOption &LO : *Section.Options) {
    OS.write(LO.Key.data(), LO.Key.size());
    OS.write('\0');
    OS.write(LO.Value.data(), LO.Value.size());
    OS.write('\0');
    SHeader.sh_size += (LO.Key.size() + LO.Value.size() + 2);
  }
}

template <class ELFT>
void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
                                         const ELFYAML::HashSection &Section,
+24 −0
Original line number Diff line number Diff line
@@ -1100,6 +1100,12 @@ static void fillMapping(IO &IO, ELFYAML::Fill &Fill) {
  IO.mapRequired("Size", Fill.Size);
}

static void sectionMapping(IO &IO, ELFYAML::LinkerOptionsSection &Section) {
  commonSectionMapping(IO, Section);
  IO.mapOptional("Options", Section.Options);
  IO.mapOptional("Content", Section.Content);
}

void MappingTraits<ELFYAML::SectionOrType>::mapping(
    IO &IO, ELFYAML::SectionOrType &sectionOrType) {
  IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
@@ -1217,6 +1223,11 @@ void MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::mapping(
      Section.reset(new ELFYAML::AddrsigSection());
    sectionMapping(IO, *cast<ELFYAML::AddrsigSection>(Section.get()));
    break;
  case ELF::SHT_LLVM_LINKER_OPTIONS:
    if (!IO.outputting())
      Section.reset(new ELFYAML::LinkerOptionsSection());
    sectionMapping(IO, *cast<ELFYAML::LinkerOptionsSection>(Section.get()));
    break;
  default:
    if (!IO.outputting()) {
      StringRef Name;
@@ -1355,6 +1366,12 @@ StringRef MappingTraits<std::unique_ptr<ELFYAML::Chunk>>::validate(
    return {};
  }

  if (const auto *Sec = dyn_cast<ELFYAML::LinkerOptionsSection>(C.get())) {
    if (Sec->Options && Sec->Content)
      return "\"Options\" and \"Content\" can't be used together";
    return {};
  }

  if (const auto *F = dyn_cast<ELFYAML::Fill>(C.get())) {
    if (!F->Pattern)
      return {};
@@ -1493,6 +1510,13 @@ void MappingTraits<ELFYAML::AddrsigSymbol>::mapping(IO &IO, ELFYAML::AddrsigSymb
  IO.mapOptional("Index", Sym.Index);
}

void MappingTraits<ELFYAML::LinkerOption>::mapping(IO &IO,
                                                   ELFYAML::LinkerOption &Opt) {
  assert(IO.getContext() && "The IO context is not initialized");
  IO.mapRequired("Name", Opt.Key);
  IO.mapRequired("Value", Opt.Value);
}

LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_AFL_REG)
LLVM_YAML_STRONG_TYPEDEF(uint8_t, MIPS_ABI_FP)
LLVM_YAML_STRONG_TYPEDEF(uint32_t, MIPS_AFL_EXT)
+69 −0
Original line number Diff line number Diff line
## Check how obj2yaml produces SHT_LLVM_LINKER_OPTIONS section descriptions.

## Check we dump valid sections using pairs of "Name" and "Value" strings.

# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: obj2yaml %t1 | FileCheck %s --check-prefix=VALID

# VALID:      - Name: .linker-options-valid1
# VALID-NEXT:   Type: SHT_LLVM_LINKER_OPTIONS
# VALID-NEXT:   Options:
# VALID-NEXT:     - Name:  a
# VALID-NEXT:       Value: b
# VALID-NEXT: - Name: .linker-options-valid2
# VALID-NEXT:   Type: SHT_LLVM_LINKER_OPTIONS
# VALID-NEXT:   Options:
# VALID-NEXT:     - Name:  a
# VALID-NEXT:       Value: b
# VALID-NEXT:     - Name:  c
# VALID-NEXT:       Value: d

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name:    .linker-options-valid1
    Type:    SHT_LLVM_LINKER_OPTIONS
    Content: "61006200"
  - Name:    .linker-options-valid2
    Type:    SHT_LLVM_LINKER_OPTIONS
    Content: "6100620063006400"

## Check we dump corrupt sections using the "Content" key.

# RUN: yaml2obj --docnum=2 %s -o %t2
# RUN: obj2yaml %t2 | FileCheck %s --check-prefix=CORRUPT

# CORRUPT:      - Name:    .linker-options-empty
# CORRUPT-NEXT:   Type:    SHT_LLVM_LINKER_OPTIONS
# CORRUPT-NEXT:   Content: ''
# CORRUPT-NEXT: - Name:    .linker-options-no-null
# CORRUPT-NEXT:   Type:    SHT_LLVM_LINKER_OPTIONS
# CORRUPT-NEXT:   Content: '610062'
# CORRUPT-NEXT: - Name:    .linker-options-incomplete
# CORRUPT-NEXT:   Type:    SHT_LLVM_LINKER_OPTIONS
# CORRUPT-NEXT:   Content: '6100'

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
## 1) Empty content.
  - Name:    .linker-options-empty
    Type:    SHT_LLVM_LINKER_OPTIONS
    Content: ""
## 2) Non-null terminated content.
  - Name:    .linker-options-no-null
    Type:    SHT_LLVM_LINKER_OPTIONS
    Content: "610062"
## 3) Odd number of strings in the section.
##   (Hence it contains an incomplete key-value pair).
  - Name:    .linker-options-incomplete
    Type:    SHT_LLVM_LINKER_OPTIONS
    Content: "6100"
+120 −0
Original line number Diff line number Diff line
## Check we are able to produce a valid SHT_LLVM_LINKER_OPTIONS
## section from its description.

## Check we can use either "Options" or "Content" to describe the data.

# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: llvm-readobj --string-dump .linker-options1 --sections --section-data %t1 \
# RUN:   | FileCheck %s --check-prefix=OPTIONS

# OPTIONS:        Name: .linker-options1
# OPTIONS-NEXT:   Type: SHT_LLVM_LINKER_OPTIONS
# OPTIONS-NEXT:   Flags [
# OPTIONS-NEXT:   ]
# OPTIONS-NEXT:   Address: 0x0
# OPTIONS-NEXT:   Offset: 0x40
# OPTIONS-NEXT:   Size: 34
# OPTIONS-NEXT:   Link: 0
# OPTIONS-NEXT:   Info: 0
# OPTIONS-NEXT:   AddressAlignment: 0
# OPTIONS-NEXT:   EntrySize: 0

# OPTIONS:      Name: .linker-options2
# OPTIONS-NEXT: Type: SHT_LLVM_LINKER_OPTIONS
# OPTIONS:      SectionData (
# OPTIONS-NEXT:   0000: 00112233 |
# OPTIONS-NEXT: )

# OPTIONS:      String dump of section '.linker-options1':
# OPTIONS-NEXT: [     0] option 0
# OPTIONS-NEXT: [     9] value 0
# OPTIONS-NEXT: [    11] option 1
# OPTIONS-NEXT: [    1a] value 1

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name: .linker-options1
    Type: SHT_LLVM_LINKER_OPTIONS
    Options:
      - Name:  option 0
        Value: value 0
      - Name:  option 1
        Value: value 1
  - Name: .linker-options2
    Type: SHT_LLVM_LINKER_OPTIONS
    Content: "00112233"

## Check that "Value" and "Name" fields are mandatory when using "Options" key.

# RUN: not yaml2obj --docnum=2 %s 2>&1 | FileCheck %s --check-prefix=NOVALUE
# RUN: not yaml2obj --docnum=3 %s 2>&1 | FileCheck %s --check-prefix=NONAME

# NOVALUE: error: missing required key 'Value'
# NONAME: error: missing required key 'Name'

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name: .linker-options
    Type: SHT_LLVM_LINKER_OPTIONS
    Options:
      - Name: name

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name: .linker-options
    Type: SHT_LLVM_LINKER_OPTIONS
    Options:
      - Value: value

## Check we can't use both "Options" and "Content" together.

# RUN: not yaml2obj %s --docnum=4 2>&1 | FileCheck %s --check-prefix=BOTH

# BOTH: error: "Options" and "Content" can't be used together
 
--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name: .linker-options
    Type: SHT_LLVM_LINKER_OPTIONS
    Options:
      - Name:  name
        Value: value
    Content: "00112233"

## Check we can omit both "Options" and "Content". This produces an empty section.

# RUN: yaml2obj %s --docnum=5 2>&1 -o %t5
# RUN: llvm-readelf --sections %t5 | FileCheck %s --check-prefix=NONE

# NONE: [Nr] Name            Type                Address          Off    Size
# NONE: [ 1] .linker-options LLVM_LINKER_OPTIONS 0000000000000000 000040 000000

--- !ELF
FileHeader:
  Class:   ELFCLASS64
  Data:    ELFDATA2LSB
  Type:    ET_REL
  Machine: EM_X86_64
Sections:
  - Name: .linker-options
    Type: SHT_LLVM_LINKER_OPTIONS
Loading