Skip to content

Commit c4e2167

Browse files
committed
[ELF] Keep st_type for symbol assignment
PR46970: for `alias = aliasee`, the alias can be used in relocation processing and on ARM st_type does affect Thumb interworking. It is thus desirable for the alias to get the same st_type. Note that the st_size field should not be inherited because some tools use st_size=0 as a heuristic to detect aliases. Retaining st_size can thwart such heuristics and cause aliases to be preferred over the original symbols. Differential Revision: https://reviews.llvm.org/D86263 (cherry picked from commit 9670029) The test symbol-assign-type.s was rewritten to not depend on 'split-file'.
1 parent d6d03d0 commit c4e2167

File tree

6 files changed

+85
-5
lines changed

6 files changed

+85
-5
lines changed

lld/ELF/LinkerScript.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ void LinkerScript::addSymbol(SymbolAssignment *cmd) {
180180
// write expressions like this: `alignment = 16; . = ALIGN(., alignment)`.
181181
uint64_t symValue = value.sec ? 0 : value.getValue();
182182

183-
Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, STT_NOTYPE,
183+
Defined newSym(nullptr, cmd->name, STB_GLOBAL, visibility, value.type,
184184
symValue, 0, sec);
185185

186186
Symbol *sym = symtab->insert(cmd->name);
@@ -317,6 +317,7 @@ void LinkerScript::assignSymbol(SymbolAssignment *cmd, bool inSec) {
317317
cmd->sym->section = v.sec;
318318
cmd->sym->value = v.getSectionOffset();
319319
}
320+
cmd->sym->type = v.type;
320321
}
321322

322323
static std::string getFilename(InputFile *file) {
@@ -1215,8 +1216,14 @@ ExprValue LinkerScript::getSymbolValue(StringRef name, const Twine &loc) {
12151216
}
12161217

12171218
if (Symbol *sym = symtab->find(name)) {
1218-
if (auto *ds = dyn_cast<Defined>(sym))
1219-
return {ds->section, false, ds->value, loc};
1219+
if (auto *ds = dyn_cast<Defined>(sym)) {
1220+
ExprValue v{ds->section, false, ds->value, loc};
1221+
// Retain the original st_type, so that the alias will get the same
1222+
// behavior in relocation processing. Any operation will reset st_type to
1223+
// STT_NOTYPE.
1224+
v.type = ds->type;
1225+
return v;
1226+
}
12201227
if (isa<SharedSymbol>(sym))
12211228
if (!errorOnMissingSection)
12221229
return {nullptr, false, 0, loc};

lld/ELF/LinkerScript.h

+4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ struct ExprValue {
5959
uint64_t val;
6060
uint64_t alignment = 1;
6161

62+
// The original st_type if the expression represents a symbol. Any operation
63+
// resets type to STT_NOTYPE.
64+
uint8_t type = llvm::ELF::STT_NOTYPE;
65+
6266
// Original source location. Used for error messages.
6367
std::string loc;
6468
};

lld/docs/ELF/linker_script.rst

+19
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,25 @@ possible. We reserve the right to make different implementation choices where
1717
it is appropriate for LLD. Intentional deviations will be documented in this
1818
file.
1919

20+
Symbol assignment
21+
~~~~~~~~~~~~~~~~~
22+
23+
A symbol assignment looks like:
24+
25+
::
26+
27+
symbol = expression;
28+
symbol += expression;
29+
30+
The first form defines ``symbol``. If ``symbol`` is already defined, it will be
31+
overridden. The other form requires ``symbol`` to be already defined.
32+
33+
For a simple assignment like ``alias = aliasee;``, the ``st_type`` field is
34+
copied from the original symbol. Any arithmetic operation (e.g. ``+ 0`` will
35+
reset ``st_type`` to ``STT_NOTYPE``.
36+
37+
The ``st_size`` field is set to 0.
38+
2039
Output section description
2140
~~~~~~~~~~~~~~~~~~~~~~~~~~
2241

lld/test/ELF/arm-thumb-interwork-ifunc.s

+11
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,27 @@
33
// RUN: ld.lld %t.o -o %t
44
// RUN: llvm-objdump --triple=armv7a-none-linux-gnueabi -d --no-show-raw-insn %t | FileCheck %s
55

6+
/// A symbol assignment defined alias inherits st_type and gets the same treatment.
7+
// RUN: llvm-mc --triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj --defsym ALIAS=1 -o %t1.o %s
8+
// RUN: ld.lld --defsym foo=foo1 %t1.o -o %t1
9+
// RUN: llvm-objdump --triple=armv7a-none-linux-gnueabi -d --no-show-raw-insn %t | FileCheck %s
10+
611
/// Non-preemptible ifuncs are called via a PLT entry which is always Arm
712
/// state, expect the ARM callers to go direct to the PLT entry, Thumb
813
/// branches are indirected via state change thunks, the bl is changed to blx.
914

1015
.syntax unified
1116
.text
1217
.balign 0x1000
18+
.ifdef ALIAS
19+
.type foo1 STT_GNU_IFUNC
20+
.globl foo1
21+
foo1:
22+
.else
1323
.type foo STT_GNU_IFUNC
1424
.globl foo
1525
foo:
26+
.endif
1627
bx lr
1728

1829
.section .text.1, "ax", %progbits

lld/test/ELF/linkerscript/common-assign.s

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
# CHECK-NEXT: Value: [[FOO]]
2828
# CHECK-NEXT: Size: 0
2929
# CHECK-NEXT: Binding: Global
30-
# CHECK-NEXT: Type: None
30+
# CHECK-NEXT: Type: Object
3131
# CHECK-NEXT: Other: 0
3232
# CHECK-NEXT: Section: .bss
3333
# CHECK-NEXT: }
@@ -36,7 +36,7 @@
3636
# CHECK-NEXT: Value: [[BAR]]
3737
# CHECK-NEXT: Size: 0
3838
# CHECK-NEXT: Binding: Global
39-
# CHECK-NEXT: Type: None
39+
# CHECK-NEXT: Type: Object
4040
# CHECK-NEXT: Other: 0
4141
# CHECK-NEXT: Section: .bss
4242
# CHECK-NEXT: }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# REQUIRES: x86
2+
## Keep st_type for simple assignment (`alias = aliasee`). This property is
3+
## desired on some targets, where symbol types can affect relocation processing
4+
## (e.g. Thumb interworking). However, the st_size field should not be retained
5+
## because some tools use st_size=0 as a heuristic to detect aliases. With any
6+
## operation, it can be argued that the new symbol may not be of the same type,
7+
## so reset st_type to STT_NOTYPE.
8+
9+
## NOTE: GNU ld retains st_type for many operations.
10+
11+
# RUN: echo 'retain1 = _start; \
12+
# RUN: retain2 = 1 ? _start : 0; \
13+
# RUN: drop1 = _start + 0; \
14+
# RUN: drop2 = 0 ? _start : 1; \
15+
# RUN: drop3 = -_start; \
16+
# RUN: ' > %t.lds
17+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
18+
# RUN: ld.lld -T %t.lds %t.o -o %t1
19+
# RUN: llvm-readelf -s %t1 | FileCheck %s
20+
21+
# CHECK: Size Type Bind Vis Ndx Name
22+
# CHECK: 1 FUNC GLOBAL DEFAULT 1 _start
23+
# CHECK: 0 FUNC GLOBAL DEFAULT 1 retain1
24+
# CHECK-NEXT: 0 FUNC GLOBAL DEFAULT 1 retain2
25+
# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT 1 drop1
26+
# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT ABS drop2
27+
# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT ABS drop3
28+
29+
# RUN: ld.lld --defsym 'retain=_start' --defsym 'drop=_start+0' %t.o -o %t2
30+
# RUN: llvm-readelf -s %t2 | FileCheck %s --check-prefix=DEFSYM
31+
32+
# DEFSYM: 0 FUNC GLOBAL DEFAULT 1 retain
33+
# DEFSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT 1 drop
34+
35+
.globl _start
36+
.type _start, @function
37+
_start:
38+
ret
39+
.size _start, 1

0 commit comments

Comments
 (0)