[PATCH] D29636: [ELF] - Added partial support for --emit-relocs (no --gc-section case) #2

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 7 07:46:30 PST 2017


I still think we should leave the DISCARD and gc case for a followup
patch. Without it this is a trivial patch.

Cheers,
Rafael

George Rimar via Phabricator <reviews at reviews.llvm.org> writes:

> grimar created this revision.
>
> It is close to https://reviews.llvm.org/D29273, but has different implementation of filtering out
> .rel[a] sections if target section was discarded.
>
> Also testcase was simplified.
>
>
> https://reviews.llvm.org/D29636
>
> Files:
>   ELF/Config.h
>   ELF/Driver.cpp
>   ELF/InputFiles.cpp
>   ELF/InputSection.cpp
>   ELF/LinkerScript.cpp
>   ELF/Options.td
>   ELF/OutputSections.cpp
>   ELF/Writer.cpp
>   test/ELF/Inputs/emit-relocs.s
>   test/ELF/emit-relocs-gc.s
>   test/ELF/emit-relocs.s
>   test/ELF/linkerscript/emit-reloc-discard.s
>
> Index: test/ELF/linkerscript/emit-reloc-discard.s
> ===================================================================
> --- test/ELF/linkerscript/emit-reloc-discard.s
> +++ test/ELF/linkerscript/emit-reloc-discard.s
> @@ -0,0 +1,14 @@
> +# REQUIRES: x86
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
> +# RUN: echo "SECTIONS { /DISCARD/ : { *(.bbb) } }" > %t.script
> +# RUN: ld.lld --emit-relocs --script %t.script %t.o -o %t1
> +# RUN: llvm-readobj -r %t1 | FileCheck %s
> +
> +# CHECK:      Relocations [
> +# CHECK-NEXT: ]
> +
> +.section .aaa,"", at progbits
> +.Lfoo:
> +
> +.section .bbb,"", at progbits
> +.long .Lfoo
> Index: test/ELF/emit-relocs.s
> ===================================================================
> --- test/ELF/emit-relocs.s
> +++ test/ELF/emit-relocs.s
> @@ -0,0 +1,98 @@
> +# REQUIRES: x86
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/emit-relocs.s -o %t2.o
> +# RUN: ld.lld --emit-relocs %t1.o %t2.o -o %t
> +# RUN: llvm-readobj -t -r %t | FileCheck %s
> +
> +## Check single dash form.
> +# RUN: ld.lld -emit-relocs %t1.o %t2.o -o %t1
> +# RUN: llvm-readobj -t -r %t1 | FileCheck %s
> +
> +## Check alias.
> +# RUN: ld.lld -q %t1.o %t2.o -o %t2
> +# RUN: llvm-readobj -t -r %t2 | FileCheck %s
> +
> +# CHECK:      Relocations [
> +# CHECK-NEXT:   Section ({{.*}}) .rela.text {
> +# CHECK-NEXT:     0x201002 R_X86_64_32 .text 0x1
> +# CHECK-NEXT:     0x201007 R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC
> +# CHECK-NEXT:     0x20100E R_X86_64_32 .text 0x1
> +# CHECK-NEXT:     0x201013 R_X86_64_PLT32 fn2 0xFFFFFFFFFFFFFFFC
> +# CHECK-NEXT:   }
> +# CHECK-NEXT: ]
> +# CHECK-NEXT: Symbols [
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name:
> +# CHECK-NEXT:     Value: 0x0
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Local
> +# CHECK-NEXT:     Type: None
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: Undefined
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name: bar
> +# CHECK-NEXT:     Value: 0x201001
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Local
> +# CHECK-NEXT:     Type: None
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name:
> +# CHECK-NEXT:     Value: 0x201000
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Local
> +# CHECK-NEXT:     Type: Section
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name: foo
> +# CHECK-NEXT:     Value: 0x20100D
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Local
> +# CHECK-NEXT:     Type: None
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name:
> +# CHECK-NEXT:     Value: 0x20100C
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Local
> +# CHECK-NEXT:     Type: Section
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name: fn
> +# CHECK-NEXT:     Value: 0x201000
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Global
> +# CHECK-NEXT:     Type: Function
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT:   Symbol {
> +# CHECK-NEXT:     Name: fn2
> +# CHECK-NEXT:     Value: 0x20100C
> +# CHECK-NEXT:     Size: 0
> +# CHECK-NEXT:     Binding: Global
> +# CHECK-NEXT:     Type: Function
> +# CHECK-NEXT:     Other: 0
> +# CHECK-NEXT:     Section: .text
> +# CHECK-NEXT:   }
> +# CHECK-NEXT: ]
> +
> +.section .text
> +.globl fn
> +.type fn, at function
> +fn:
> + nop
> +
> +bar:
> +  movl $bar, %edx
> +  callq fn at PLT
> +  nop
> Index: test/ELF/emit-relocs-gc.s
> ===================================================================
> --- test/ELF/emit-relocs-gc.s
> +++ test/ELF/emit-relocs-gc.s
> @@ -0,0 +1,5 @@
> +# REQUIRES: x86
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
> +# RUN: not ld.lld --gc-sections --emit-relocs %t1.o -o %t 2>&1 \
> +# RUN:    | FileCheck -check-prefix=ERR %s
> +# ERR: --emit-relocs and --gc-sections may not be used together
> Index: test/ELF/Inputs/emit-relocs.s
> ===================================================================
> --- test/ELF/Inputs/emit-relocs.s
> +++ test/ELF/Inputs/emit-relocs.s
> @@ -0,0 +1,10 @@
> +.section .text
> +.globl fn2
> +.type fn2, at function
> +fn2:
> + nop
> +
> +foo:
> +  movl $foo, %edx
> +  callq fn2 at PLT
> +  nop
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -449,9 +449,9 @@
>    if (B.isFile())
>      return false;
>  
> -  // We keep sections in symtab for relocatable output.
> +  // We keep sections in symtab for relocatable output and --emit-reloc.
>    if (B.isSection())
> -    return Config->Relocatable;
> +    return Config->Relocatable || Config->EmitRelocs;
>  
>    // If sym references a section in a discarded group, don't keep it.
>    if (Sec == &InputSection<ELFT>::Discarded)
> Index: ELF/OutputSections.cpp
> ===================================================================
> --- ELF/OutputSections.cpp
> +++ ELF/OutputSections.cpp
> @@ -116,7 +116,8 @@
>    }
>  
>    uint32_t Type = this->Type;
> -  if (!Config->Relocatable || (Type != SHT_RELA && Type != SHT_REL))
> +  if ((!Config->Relocatable && !Config->EmitRelocs) ||
> +      (Type != SHT_RELA && Type != SHT_REL))
>      return;
>  
>    this->Link = In<ELFT>::SymTab->OutSec->SectionIndex;
> Index: ELF/Options.td
> ===================================================================
> --- ELF/Options.td
> +++ ELF/Options.td
> @@ -70,6 +70,8 @@
>  def eh_frame_hdr: F<"eh-frame-hdr">,
>    HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">;
>  
> +def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
> +
>  def enable_new_dtags: F<"enable-new-dtags">,
>    HelpText<"Enable new dynamic tags">;
>  
> @@ -283,6 +285,7 @@
>  def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
>  def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
>  def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
> +def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>;
>  def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
>  def alias_entry_entry: J<"entry=">, Alias<entry>;
>  def alias_error_limit: J<"error-limit=">, Alias<error_limit>;
> Index: ELF/LinkerScript.cpp
> ===================================================================
> --- ELF/LinkerScript.cpp
> +++ ELF/LinkerScript.cpp
> @@ -288,6 +288,20 @@
>    return Ret;
>  }
>  
> +template <class ELFT> static void scanRelocationSections() {
> +  for (InputSectionBase<ELFT> *S : Symtab<ELFT>::X->Sections) {
> +    if (S->Type != SHT_REL && S->Type != SHT_RELA)
> +      continue;
> +    InputSection<ELFT> *IS = cast<InputSection<ELFT>>(S);
> +    if (!IS->getFile())
> +      continue;
> +    ArrayRef<InputSectionBase<ELFT> *> Sections = IS->getFile()->getSections();
> +    InputSectionBase<ELFT> *Target = Sections[IS->Info];
> +    if (Target == &InputSection<ELFT>::Discarded || !Target->Live)
> +      S->Live = false;
> +  }
> +}
> +
>  template <class ELFT>
>  void LinkerScript<ELFT>::addSection(OutputSectionFactory<ELFT> &Factory,
>                                      InputSectionBase<ELFT> *Sec,
> @@ -366,6 +380,12 @@
>          addSection(Factory, S, Cmd->Name);
>      }
>    }
> +
> +  // When --emit-relocs is used, we leave .rel[a]* sections in the output.
> +  // If target section was discarded from script, we should not emit the
> +  // relocation section for it. scanRelocationSections() handles that case.
> +  if (Config->EmitRelocs)
> +    scanRelocationSections<ELFT>();
>  }
>  
>  // Add sections that didn't match any sections command.
> Index: ELF/InputSection.cpp
> ===================================================================
> --- ELF/InputSection.cpp
> +++ ELF/InputSection.cpp
> @@ -214,9 +214,9 @@
>    return Sections[this->Info];
>  }
>  
> -// This is used for -r. We can't use memcpy to copy relocations because we need
> -// to update symbol table offset and section index for each relocation. So we
> -// copy relocations one by one.
> +// This is used for -r and --emit-relocs. We can't use memcpy to copy
> +// relocations because we need to update symbol table offset and section index
> +// for each relocation. So we copy relocations one by one.
>  template <class ELFT>
>  template <class RelTy>
>  void InputSection<ELFT>::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) {
> @@ -235,7 +235,11 @@
>  
>      if (Config->Rela)
>        P->r_addend = getAddend<ELFT>(Rel);
> -    P->r_offset = RelocatedSection->getOffset(Rel.r_offset);
> +
> +    // Output section VA is zero for -r, so r_offset is an offset within the
> +    // section, but for --emit-relocs it is an absolute address.
> +    P->r_offset = RelocatedSection->OutSec->Addr +
> +                  RelocatedSection->getOffset(Rel.r_offset);
>      P->setSymbolAndType(In<ELFT>::SymTab->getSymbolIndex(&Body), Type,
>                          Config->Mips64EL);
>    }
> @@ -514,7 +518,8 @@
>      return;
>    }
>  
> -  // If -r is given, then an InputSection may be a relocation section.
> +  // If -r or --emit-relocs is given, then an InputSection
> +  // may be a relocation section.
>    if (this->Type == SHT_RELA) {
>      copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
>      return;
> Index: ELF/InputFiles.cpp
> ===================================================================
> --- ELF/InputFiles.cpp
> +++ ELF/InputFiles.cpp
> @@ -399,6 +399,18 @@
>      }
>      assert(isUInt<31>(NumRelocations));
>      Target->NumRelocations = NumRelocations;
> +
> +    // Relocation sections processed by the linker are usually removed
> +    // from the output, so returning `nullptr` for the normal case.
> +    // However, if -emit-relocs is given, we need to leave them in the output.
> +    // (Some post link analysis tools need this information.)
> +    if (Config->EmitRelocs) {
> +      if (!isa<InputSection<ELFT>>(Target))
> +        fatal(toString(this) + ": --emit-relocs for relocations sections "
> +                               "pointing to .eh_frame is not supported due to "
> +                               "an implementation limitation");
> +      return make<InputSection<ELFT>>(this, &Sec, Name);
> +    }
>      return nullptr;
>    }
>    }
> Index: ELF/Driver.cpp
> ===================================================================
> --- ELF/Driver.cpp
> +++ ELF/Driver.cpp
> @@ -234,6 +234,11 @@
>      if (Config->Pie)
>        error("-r and -pie may not be used together");
>    }
> +
> +  // -emit-relocs and -gc-sections don't conflict in theory, but LLD currently
> +  // does not support the combination due to an implementation limitation.
> +  if (Config->EmitRelocs && Config->GcSections)
> +    error("--emit-relocs and --gc-sections may not be used together");
>  }
>  
>  static StringRef getString(opt::InputArgList &Args, unsigned Key,
> @@ -519,6 +524,7 @@
>    Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
>    Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
>    Config->DisableVerify = Args.hasArg(OPT_disable_verify);
> +  Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
>    Config->EhFrameHdr = Args.hasArg(OPT_eh_frame_hdr);
>    Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags);
>    Config->ExportDynamic =
> Index: ELF/Config.h
> ===================================================================
> --- ELF/Config.h
> +++ ELF/Config.h
> @@ -102,6 +102,7 @@
>    bool Demangle = true;
>    bool DisableVerify;
>    bool EhFrameHdr;
> +  bool EmitRelocs;
>    bool EnableNewDtags;
>    bool ExportDynamic;
>    bool FatalWarnings;


More information about the llvm-commits mailing list