Skip to content

[ELF] Error if a section address is smaller than image base #140187

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions lld/ELF/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1614,18 +1614,33 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
for (OutputSection *sec : ctx.outputSections)
sec->addr = 0;

// If addrExpr is set, the address may not be a multiple of the alignment.
// Warn because this is error-prone.
for (SectionCommand *cmd : ctx.script->sectionCommands)
if (auto *osd = dyn_cast<OutputDesc>(cmd)) {
OutputSection *osec = &osd->osec;
if (osec->addr % osec->addralign != 0)
Warn(ctx) << "address (0x" << Twine::utohexstr(osec->addr)
<< ") of section " << osec->name
<< " is not a multiple of alignment (" << osec->addralign
<< ")";
uint64_t imageBase = ctx.script->hasSectionsCommand || ctx.arg.relocatable
? 0
: ctx.target->getImageBase();
for (SectionCommand *cmd : ctx.script->sectionCommands) {
auto *osd = dyn_cast<OutputDesc>(cmd);
if (!osd)
continue;
OutputSection *osec = &osd->osec;
// Error if the address is below the image base when SECTIONS is absent
// (e.g. when -Ttext is specified and smaller than the default target image
// base for no-pie).
if (osec->addr < imageBase && (osec->flags & SHF_ALLOC)) {
Err(ctx) << "section '" << osec->name << "' address (0x"
<< Twine::utohexstr(osec->addr)
<< ") is smaller than image base (0x"
<< Twine::utohexstr(imageBase) << "); specify --image-base";
}

// If addrExpr is set, the address may not be a multiple of the alignment.
// Warn because this is error-prone.
if (osec->addr % osec->addralign != 0)
Warn(ctx) << "address (0x" << Twine::utohexstr(osec->addr)
<< ") of section " << osec->name
<< " is not a multiple of alignment (" << osec->addralign
<< ")";
}

// Sizes are no longer allowed to grow, so all allowable spills have been
// taken. Remove any leftover potential spills.
ctx.script->erasePotentialSpillSections();
Expand Down
6 changes: 6 additions & 0 deletions lld/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ Breaking changes
in the same segment by default. Pass ``--xosegment`` to lld in order to get
the old behavior back.

* When using ``--no-pie`` without a ``SECTIONS`` command, the linker uses the
target's default image base. If ``-Ttext=`` or ``--section-start`` specifies
an output section address below this base, there will now be an error.
``--image-base`` can be set at a lower address to fix the error.
(`#140187 <https://github.com/llvm/llvm-project/pull/140187>`_)

COFF Improvements
-----------------

Expand Down
12 changes: 12 additions & 0 deletions lld/test/ELF/linkerscript/out-of-order.s
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@
# CHECK-NEXT: 5 .hash 00000010 000000000000201c
# CHECK-NEXT: 6 .text 00000008 000000000000202c

# RUN: ld.lld -e 0 -o %t --script %t.script %t.o --fatal-warnings
# RUN: llvm-readelf -Sl %t | FileCheck %s --check-prefix=CHECK1

# CHECK1: Name Type Address Off Size ES Flg Lk Inf Al
# CHECK1-NEXT: NULL 0000000000000000 000000 000000 00 0 0 0
# CHECK1-NEXT: .text PROGBITS 0000000000000000 001000 000008 00 AX 0 0 4
# CHECK1-NEXT: .data PROGBITS 0000000000004000 002000 000008 00 WA 0 0 1
# CHECK1: Program Headers:
# CHECK1-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK1-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000008 0x000008 R E 0x1000
# CHECK1-NEXT: LOAD 0x002000 0x0000000000004000 0x0000000000004000 0x000008 0x000008 RW 0x1000

.quad 0
.data
.quad 0
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript/section-align2.test
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# RUN: llvm-readelf -S %t | FileCheck %s

## Check we don't warn in the absence of SECTIONS.
# RUN: ld.lld --fatal-warnings -Ttext=0x10000 %t.o -o /dev/null
# RUN: ld.lld --fatal-warnings -Ttext=0x10000 --image-base=0x10000 %t.o -o /dev/null

# WARN: warning: address (0x10004) of section .data.rel.ro is not a multiple of alignment (16)
# WARN: warning: address (0x20001) of section .data2 is not a multiple of alignment (8)
Expand Down
25 changes: 18 additions & 7 deletions lld/test/ELF/sectionstart.s
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
# RUN: not ld.lld %t.o --section-start .text=0x100000 \
# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000
# RUN: ld.lld %t.o --section-start .text=0x100000 \
# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000 -o %t
# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000 --noinhibit-exec -o %t 2>&1 | \
# RUN: FileCheck %s --check-prefix=LINK --implicit-check-not=warning:
# RUN: llvm-objdump --section-headers %t | FileCheck %s

# LINK: warning: section '.text' address (0x100000) is smaller than image base (0x200000); specify --image-base
# LINK-NEXT: warning: section '.data' address (0x110000) is smaller than image base (0x200000); specify --image-base

# CHECK: Sections:
# CHECK-NEXT: Idx Name Size VMA Type
# CHECK-NEXT: 0 00000000 0000000000000000
# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT
# CHECK-NEXT: 2 .data 00000004 0000000000110000 DATA
# CHECK-NEXT: 3 .bss 00000004 0000000000200000 BSS

## The same, but dropped "0x" prefix.
# RUN: ld.lld %t.o --section-start .text=100000 \
# RUN: --section-start .data=110000 --section-start .bss=0x200000 -o %t1
## The errors go away when the image base is 0.
# RUN: ld.lld %t.o -pie --section-start .text=0x100000 \
# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000 -o %t 2>&1 | count 0
# RUN: llvm-objdump --section-headers %t | FileCheck %s

## The same, but dropped "0x" prefix. Specify a smaller --image-base to suppress warnings.
# RUN: ld.lld %t.o --image-base=0x90000 --section-start .text=100000 \
# RUN: --section-start .data=110000 --section-start .bss=0x200000 -o %t1 2>&1 | count 0
# RUN: llvm-objdump --section-headers %t1 | FileCheck %s

## Use -Ttext, -Tdata, -Tbss as replacement for --section-start:
# RUN: ld.lld %t.o -Ttext=0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4
# RUN: ld.lld %t.o --image-base=0x90000 -Ttext=0x100000 -Tdata=0x110000 -Tbss=0x200000 -o %t4
# RUN: llvm-objdump --section-headers %t4 | FileCheck %s

## The same, but dropped "0x" prefix.
# RUN: ld.lld %t.o -Ttext=100000 -Tdata=110000 -Tbss=200000 -o %t5
# RUN: ld.lld %t.o --image-base=0x90000 -Ttext=100000 -Tdata=110000 -Tbss=200000 -o %t5
# RUN: llvm-objdump --section-headers %t5 | FileCheck %s

## Check form without assignment:
# RUN: ld.lld %t.o -Ttext 0x100000 -Tdata 0x110000 -Tbss 0x200000 -o %t4
# RUN: ld.lld %t.o --image-base=0x90000 -Ttext 0x100000 -Tdata 0x110000 -Tbss 0x200000 -o %t4
# RUN: llvm-objdump --section-headers %t4 | FileCheck %s

## Errors:
Expand Down
4 changes: 3 additions & 1 deletion lld/test/ELF/ttext-tdata-tbss.s
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
## If -Ttext is smaller than the image base (which defaults to 0x200000 for -no-pie),
## the headers will still be allocated, but mapped at a higher address,
## which may look strange.
# RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o -o %t2
# RUN: ld.lld -Ttext 0x0 -Tdata 0x4000 -Tbss 0x8000 %t.o --noinhibit-exec -o %t2 2>&1 | FileCheck %s --check-prefix=LINK1
# RUN: llvm-readelf -S -l %t2 | FileCheck %s --check-prefix=USER1
# LINK1: warning: section '.text' address (0x0) is smaller than image base (0x200000); specify --image-base
# LINK1-NEXT: warning: section '.data' address (0x4000) is smaller than image base (0x200000); specify --image-base
# USER1: .text PROGBITS 0000000000000000 001000 000001
# USER1-NEXT: .data PROGBITS 0000000000004000 002000 000008
# USER1-NEXT: .bss NOBITS 0000000000008000 002008 000008
Expand Down
Loading