diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -58,6 +58,7 @@ uint64_t val; uint64_t alignment = 1; + uint8_t type = 0; // Original source location. Used for error messages. std::string loc; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -317,6 +317,7 @@ cmd->sym->section = v.sec; cmd->sym->value = v.getSectionOffset(); } + cmd->sym->type = v.type; } static std::string getFilename(InputFile *file) { @@ -1223,8 +1224,13 @@ } if (Symbol *sym = symtab->find(name)) { - if (auto *ds = dyn_cast(sym)) - return {ds->section, false, ds->value, loc}; + if (auto *ds = dyn_cast(sym)) { + ExprValue v{ds->section, false, ds->value, loc}; + // Retain the original st_type, so that the alias will get the same + // behavior in relocation processing. + v.type = ds->type; + return v; + } if (isa(sym)) if (!errorOnMissingSection) return {nullptr, false, 0, loc}; diff --git a/lld/test/ELF/linkerscript/common-assign.s b/lld/test/ELF/linkerscript/common-assign.s --- a/lld/test/ELF/linkerscript/common-assign.s +++ b/lld/test/ELF/linkerscript/common-assign.s @@ -27,7 +27,7 @@ # CHECK-NEXT: Value: [[FOO]] # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global -# CHECK-NEXT: Type: None +# CHECK-NEXT: Type: Object # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .bss # CHECK-NEXT: } @@ -36,7 +36,7 @@ # CHECK-NEXT: Value: [[BAR]] # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global -# CHECK-NEXT: Type: None +# CHECK-NEXT: Type: Object # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .bss # CHECK-NEXT: } diff --git a/lld/test/ELF/linkerscript/symbol-assign-type.s b/lld/test/ELF/linkerscript/symbol-assign-type.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/linkerscript/symbol-assign-type.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +## Keep st_type for simple assignment (`aliase = aliasee`). This property is +## desired on some targets, where symbol types can affect relocation processing +## (e.g. Thumb interworking). However, the st_size field should not be retained +## because some tools use st_size=0 as a heuristic to detect aliases. With any +## operation, it can be argued that the new symbol may not be of the same type, +## so reset st_type to STT_NOTYPE. + +## NOTE: GNU ld retains st_type for many operations. + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/main.s -o %t.o +# RUN: ld.lld -T %t/a.lds %t.o -o %t1 +# RUN: llvm-readelf -s %t1 | FileCheck %s + +# CHECK: Size Type Bind Vis Ndx Name +# CHECK: 0 FUNC GLOBAL DEFAULT 1 retain1 +# CHECK-NEXT: 0 FUNC GLOBAL DEFAULT 1 retain2 +# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT 1 drop1 +# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT ABS drop2 +# CHECK-NEXT: 0 NOTYPE GLOBAL DEFAULT ABS drop3 + +# RUN: ld.lld --defsym 'retain=_start' --defsym 'drop=_start+0' %t.o -o %t2 +# RUN: llvm-readelf -s %t2 | FileCheck %s --check-prefix=DEFSYM + +# DEFSYM: 0 FUNC GLOBAL DEFAULT 1 retain +# DEFSYM-NEXT: 0 NOTYPE GLOBAL DEFAULT 1 drop + +#--- a.lds +retain1 = _start; +retain2 = 1 ? _start : 0; + +## Reset to STT_NOTYPE if any operation is performed, +## even if the operation is an identity function. +drop1 = _start + 0; +drop2 = 0 ? _start : 1; +drop3 = -_start; + +#--- main.s +.globl _start +.type _start, @function +_start: + ret +.size _start, 1