[PATCH] D27516: [ELF] - Place ".text" to be first section if -Ttext is used.

Rafael Avila de Espindola via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 7 10:40:35 PST 2016


Oh, is the loader trying to set the address of the section .text or of
the PT_LOAD? If the section, what exactly is it trying to do?

If it has expectations on the section order it seems better to use a
linker script.

If what it really wants is to set a particular section at a particular
address, I think we can implement that, but as Rui points out we should
have a general solution.

One such solution would be to put all section with specified addresses
before other sections and to order them based of the address value.

I don't think we should try to do something fancier like looking for an
empty spot when placing each section.


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

> grimar created this revision.
> grimar added reviewers: ruiu, rafael.
> grimar added subscribers: llvm-commits, grimar, evgeny777.
>
> Some loaders, for example one from PR31295 use -N -Ttext combination.
> Previously our output was in next order:
>
>   .rodata
>   .text
>   ...
>
> That caused an issue. Imagine .rodata was assigned to 0x10000 and then -Ttext sets .text below that.
> That could cause sections addresses intersections.
> Both GNU linkers able handles that correctly.
>
> gold just places .text to be first section. In that case
> we can start assigning VA from -Ttext value if was specified and do that in a forward loop, just like we 
> already do in void Writer<ELFT>::assignAddresses().
> That is what this patch implements.
>
>
> https://reviews.llvm.org/D27516
>
> Files:
>   ELF/Writer.cpp
>   test/ELF/ttext.s
>
>
> Index: test/ELF/ttext.s
> ===================================================================
> --- test/ELF/ttext.s
> +++ test/ELF/ttext.s
> @@ -0,0 +1,27 @@
> +# REQUIRES: x86
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
> +
> +# RUN: ld.lld -N %t -o %t1
> +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
> +# CHECK:      Sections:
> +# CHECK-NEXT: Idx Name         Size      Address         Type
> +# CHECK-NEXT:   0              00000000 0000000000000000
> +# CHECK-NEXT:   1 .rodata      00000008 00000000002000e8 DATA
> +# CHECK-NEXT:   2 .text        00000001 00000000002000f0 TEXT DATA
> +
> +## Check that sections does not intersect if -Ttext used.
> +# RUN: ld.lld -N -Ttext 0x2000e8 %t -o %t1
> +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s --check-prefix=TEXT
> +# TEXT:      Sections:
> +# TEXT-NEXT: Idx Name       Size      Address         Type
> +# TEXT-NEXT:   0            00000000 0000000000000000
> +# TEXT-NEXT:   1 .text      00000001 00000000002000e8 TEXT DATA
> +# TEXT-NEXT:   2 .rodata    00000008 00000000002000e9 DATA
> +
> +.text
> +.globl _start
> +_start:
> + nop
> +
> +.section .rodata,"a"
> + .quad 1
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -482,7 +482,18 @@
>  template <class ELFT>
>  static bool compareSectionsNonScript(const OutputSectionBase *A,
>                                       const OutputSectionBase *B) {
> -  // Put .interp first because some loaders want to see that section
> +  // Some loaders use -Ttext option to set .text section address.
> +  // In that case we place it at the begining to be able to
> +  // assign VA in a simple forward loop later. That is consistent
> +  // with what GNU gold do.
> +  if (Config->SectionStartMap.count(".text")) {
> +    bool AIsText = A->getName() == ".text";
> +    bool BIsText = B->getName() == ".text";
> +    if (AIsText != BIsText)
> +      return AIsText;
> +  }
> +
> +  // Put .interp early because some loaders want to see that section
>    // on the first page of the executable file when loaded into memory.
>    bool AIsInterp = A->getName() == ".interp";
>    bool BIsInterp = B->getName() == ".interp";
>
>
> Index: test/ELF/ttext.s
> ===================================================================
> --- test/ELF/ttext.s
> +++ test/ELF/ttext.s
> @@ -0,0 +1,27 @@
> +# REQUIRES: x86
> +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
> +
> +# RUN: ld.lld -N %t -o %t1
> +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s
> +# CHECK:      Sections:
> +# CHECK-NEXT: Idx Name         Size      Address         Type
> +# CHECK-NEXT:   0              00000000 0000000000000000
> +# CHECK-NEXT:   1 .rodata      00000008 00000000002000e8 DATA
> +# CHECK-NEXT:   2 .text        00000001 00000000002000f0 TEXT DATA
> +
> +## Check that sections does not intersect if -Ttext used.
> +# RUN: ld.lld -N -Ttext 0x2000e8 %t -o %t1
> +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s --check-prefix=TEXT
> +# TEXT:      Sections:
> +# TEXT-NEXT: Idx Name       Size      Address         Type
> +# TEXT-NEXT:   0            00000000 0000000000000000
> +# TEXT-NEXT:   1 .text      00000001 00000000002000e8 TEXT DATA
> +# TEXT-NEXT:   2 .rodata    00000008 00000000002000e9 DATA
> +
> +.text
> +.globl _start
> +_start:
> + nop
> +
> +.section .rodata,"a"
> + .quad 1
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -482,7 +482,18 @@
>  template <class ELFT>
>  static bool compareSectionsNonScript(const OutputSectionBase *A,
>                                       const OutputSectionBase *B) {
> -  // Put .interp first because some loaders want to see that section
> +  // Some loaders use -Ttext option to set .text section address.
> +  // In that case we place it at the begining to be able to
> +  // assign VA in a simple forward loop later. That is consistent
> +  // with what GNU gold do.
> +  if (Config->SectionStartMap.count(".text")) {
> +    bool AIsText = A->getName() == ".text";
> +    bool BIsText = B->getName() == ".text";
> +    if (AIsText != BIsText)
> +      return AIsText;
> +  }
> +
> +  // Put .interp early because some loaders want to see that section
>    // on the first page of the executable file when loaded into memory.
>    bool AIsInterp = A->getName() == ".interp";
>    bool BIsInterp = B->getName() == ".interp";


More information about the llvm-commits mailing list