[lld] [ELF] Warn if specified section address is smaller than image base (PR #140187)

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Fri May 16 09:42:34 PDT 2025


MaskRay wrote:

Thanks for the analysis!
The GNU ld's text segment concept, often (ab)used to specify the image base, doesn't align well with our layout, which places .rodata before .text and uses the --rosegment option.
Our layout offers advantages like better -z separate-segment and PT_GNU_RELRO support with smaller file size, but it requires adjustments when users specify -Ttext or -Ttext-segment options.
To maintain simpler layout rules, we intentionally reject certain GNU ld behaviors, such as -Ttext-segment (https://reviews.llvm.org/D70468).

When there is a PT_LOAD segment that covers ELF header/program headers but no sections

* In the default --ro-segment case, the output is correct, though it may appear unusual (ignoring the non-ascending p_vaddr for now).
* In the --no-rosegment case, an `error: output file too large` occurs.

I agree that this diagnostic should be elevated to an error for clarity.
I have mild preference that we don't change program header allocation behavior

37 tests that use -Ttext= will need adjustment.
```
Failed Tests (37):
  lld :: ELF/aarch64-reloc-implicit-addend.test
  lld :: ELF/aarch64-thunk-align.s
  lld :: ELF/arm-cmse-diagnostics.s
  lld :: ELF/arm-cmse-implib.s
  lld :: ELF/arm-cmse-keep-sections.s
  lld :: ELF/arm-cmse-noveneers.s
  lld :: ELF/arm-cmse-secure.s
  lld :: ELF/arm-cmse-veneers.s
  lld :: ELF/avr-reloc-error.s
  lld :: ELF/basic-avr.s
  lld :: ELF/compress-debug-sections-reloc.s
  lld :: ELF/eh-frame-value-format7.s
  lld :: ELF/eh-frame-value-format8.s
  lld :: ELF/gdb-index-dwarf5-type-unit.s
  lld :: ELF/gdb-index-icf.s
  lld :: ELF/i386-pc16.test
  lld :: ELF/i386-pc8.s
  lld :: ELF/i386-reloc-16-large-addend.s
  lld :: ELF/i386-reloc-8-large-addend.s
  lld :: ELF/i386-reloc-large-addend.s
  lld :: ELF/i386-reloc-range.s
  lld :: ELF/i386-reloc8-reloc16-addend.s
  lld :: ELF/just-symbols-cref.s
  lld :: ELF/just-symbols.s
  lld :: ELF/linkerscript/avr5.test
  lld :: ELF/linkerscript/memory-no-sections.test
  lld :: ELF/loongarch-pc-aligned.s
  lld :: ELF/msp430.s
  lld :: ELF/nmagic.s
  lld :: ELF/oformat-binary-ttext.s
  lld :: ELF/sectionstart-noallochdr.s
  lld :: ELF/systemz-reloc-disp12.s
  lld :: ELF/systemz-reloc-disp20.s
  lld :: ELF/systemz-reloc-pc16.s
  lld :: ELF/systemz-reloc-pc32.s
  lld :: ELF/x86-64-reloc-32.s
  lld :: ELF/x86-64-reloc-pc32.s
```

(Assemble sectionstart.s to a.o)
```
% /tmp/Debug/bin/ld.lld a.o -Ttext=0x3000 -o a && readelf -W -Sl a
ld.lld: warning: section '.text' address (0x3000) is smaller than image base (0x200000); specify --image-base
ld.lld: warning: section '.data' address (0x4001) is smaller than image base (0x200000); specify --image-base
ld.lld: warning: section '.bss' address (0x4005) is smaller than image base (0x200000); specify --image-base
There are 8 section headers, starting at offset 0x1088:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        0000000000003000 001000 000001 00  AX  0   0  4
  [ 2] .data             PROGBITS        0000000000004001 001001 000004 00  WA  0   0  1
  [ 3] .bss              NOBITS          0000000000004005 001005 000004 00  WA  0   0  1
  [ 4] .comment          PROGBITS        0000000000000000 001005 000013 01  MS  0   0  1
  [ 5] .symtab           SYMTAB          0000000000000000 001018 000030 18      7   1  8
  [ 6] .shstrtab         STRTAB          0000000000000000 001048 000035 00      0   0  1
  [ 7] .strtab           STRTAB          0000000000000000 00107d 000008 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

Elf file type is EXEC (Executable file)
Entry point 0x3000
There are 5 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000200040 0x0000000000200040 0x000118 0x000118 R   0x8
  LOAD           0x000000 0x0000000000200000 0x0000000000200000 0x000158 0x000158 R   0x1000
  LOAD           0x001000 0x0000000000003000 0x0000000000003000 0x000001 0x000001 R E 0x1000
  LOAD           0x001001 0x0000000000004001 0x0000000000004001 0x000004 0x000008 RW  0x1000
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0

 Section to Segment mapping:
  Segment Sections...
   00
   01
   02     .text
   03     .data .bss
   04

% /tmp/Debug/bin/ld.lld --no-rosegment -Ttext 0x3000 a.o -o a3 && readelf -W -Sl a3
ld.lld: warning: section '.text' address (0x3000) is smaller than image base (0x200000); specify --image-base
ld.lld: warning: section '.data' address (0x4001) is smaller than image base (0x200000); specify --image-base
ld.lld: warning: section '.bss' address (0x4005) is smaller than image base (0x200000); specify --image-base
ld.lld: error: output file too large: 18446744073707467400 bytes
section sizes:
.text 1
.data 4
.bss 4
.comment 19
.symtab 48
.shstrtab 53
.strtab 8
```


https://github.com/llvm/llvm-project/pull/140187


More information about the llvm-commits mailing list