Skip to content

Commit 144d127

Browse files
authored
[lld] [MTE] Drop MTE globals for fully static executables, not ban (#68217)
Integrating MTE globals on Android revealed a lot of cases where libraries are built as both archives and DSOs, and they're linked into fully static and dynamic executables respectively. MTE globals doesn't work for fully static executables. They need a dynamic loader to process the special R_AARCH64_RELATIVE relocation semantics with the encoded offset. Fully static executables that had out-of-bounds derived symbols (like 'int* foo_end = foo[16]') crash under MTE globals w/ static executables. So, LLD in its current form simply errors out when you try and compile a fully static executable that has a single MTE global variable in it. It seems like a much better idea to simply have LLD not do the special work for MTE globals in fully static contexts, and to drop any unnecessary metadata. This means that you can build archives with MTE globals and link them into both fully-static and dynamic executables.
1 parent f4defbf commit 144d127

File tree

6 files changed

+88
-11
lines changed

6 files changed

+88
-11
lines changed

lld/ELF/Driver.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,8 +3029,7 @@ void LinkerDriver::link(opt::InputArgList &args) {
30293029
// partition.
30303030
copySectionsIntoPartitions();
30313031

3032-
if (config->emachine == EM_AARCH64 &&
3033-
config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) {
3032+
if (canHaveMemtagGlobals()) {
30343033
llvm::TimeTraceScope timeScope("Process memory tagged symbols");
30353034
createTaggedSymbols(ctx.objectFiles);
30363035
}

lld/ELF/InputFiles.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,16 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
624624
}
625625
}
626626

627+
// Producing a static binary with MTE globals is not currently supported,
628+
// remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused
629+
// medatada, and we don't want them to end up in the output file for static
630+
// executables.
631+
if (sec.sh_type == SHT_AARCH64_MEMTAG_GLOBALS_STATIC &&
632+
!canHaveMemtagGlobals()) {
633+
this->sections[i] = &InputSection::discarded;
634+
continue;
635+
}
636+
627637
if (sec.sh_type != SHT_GROUP)
628638
continue;
629639
StringRef signature = getShtGroupSignature(objSections, sec);

lld/ELF/Writer.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,18 @@ void elf::addReservedSymbols() {
251251
ElfSym::edata2 = add("_edata", -1);
252252
}
253253

254+
// Fully static executables don't support MTE globals at this point in time, as
255+
// we currently rely on:
256+
// - A dynamic loader to process relocations, and
257+
// - Dynamic entries.
258+
// This restriction could be removed in future by re-using some of the ideas
259+
// that ifuncs use in fully static executables.
260+
bool elf::canHaveMemtagGlobals() {
261+
return config->emachine == EM_AARCH64 &&
262+
config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE &&
263+
(config->relocatable || config->shared || needsInterpSection());
264+
}
265+
254266
static OutputSection *findSection(StringRef name, unsigned partition = 1) {
255267
for (SectionCommand *cmd : script->sectionCommands)
256268
if (auto *osd = dyn_cast<OutputDesc>(cmd))
@@ -345,11 +357,7 @@ template <class ELFT> void elf::createSyntheticSections() {
345357
std::make_unique<SymbolTableSection<ELFT>>(*part.dynStrTab);
346358
part.dynamic = std::make_unique<DynamicSection<ELFT>>();
347359

348-
if (config->emachine == EM_AARCH64 &&
349-
config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE) {
350-
if (!config->relocatable && !config->shared && !needsInterpSection())
351-
error("--android-memtag-mode is incompatible with fully-static "
352-
"executables (-static)");
360+
if (canHaveMemtagGlobals()) {
353361
part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>();
354362
add(*part.memtagAndroidNote);
355363
part.memtagDescriptors = std::make_unique<MemtagDescriptors>();

lld/ELF/Writer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
5656
bool isMipsN32Abi(const InputFile *f);
5757
bool isMicroMips();
5858
bool isMipsR6();
59+
60+
bool canHaveMemtagGlobals();
5961
} // namespace lld::elf
6062

6163
#endif

lld/test/ELF/Inputs/aarch64-memtag-globals.s

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,3 +380,38 @@ global_extern_const_definition_but_nonconst_import:
380380
global_extern_untagged_definition_but_tagged_import:
381381
.word 0
382382
.size global_extern_untagged_definition_but_tagged_import, 4
383+
384+
#--- input_3.s
385+
## Generated with:
386+
##
387+
## - clang <input_file.c> -fsanitize=memtag-globals -O2 -S -o - \
388+
## --target=aarch64-linux-android31 -fno-asynchronous-unwind-tables
389+
##
390+
## <input_file.c> contents:
391+
##
392+
## int global_extern_outside_this_dso;
393+
##
394+
## int main() {
395+
## return 0;
396+
## }
397+
398+
.text
399+
.file "main.c"
400+
.globl main // -- Begin function main
401+
.p2align 2
402+
.type main,@function
403+
main: // @main
404+
// %bb.0: // %entry
405+
mov w0, wzr
406+
ret
407+
.Lfunc_end0:
408+
.size main, .Lfunc_end0-main
409+
// -- End function
410+
.memtag global_extern_outside_this_dso // @global_extern_outside_this_dso
411+
.type global_extern_outside_this_dso,@object
412+
.bss
413+
.globl global_extern_outside_this_dso
414+
.p2align 4, 0x0
415+
global_extern_outside_this_dso:
416+
.zero 16
417+
.size global_extern_outside_this_dso, 16

lld/test/ELF/aarch64-memtag-globals.s

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,33 @@ Symbols:
7373
# RUN: %t1.o %t2.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-DYNRELOC
7474
# CHECK-DYNRELOC: --apply-dynamic-relocs cannot be used with MTE globals
7575

76-
## And ensure that fully-static executables are banned.
77-
# RUN: not ld.lld --static --android-memtag-mode=sync \
78-
# RUN: %t1.o %t2.o -o %t1.so 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTATIC
79-
# CHECK-NOSTATIC: --android-memtag-mode is incompatible with fully-static executables (-static)
76+
## Ensure that fully statically linked executables just simply drop the MTE
77+
## globals stuff: special relocations, data in the place to be relocated,
78+
## dynamic entries, etc.
79+
# RUN: llvm-mc --filetype=obj -triple=aarch64-none-linux-android \
80+
# RUN: %t/input_3.s -o %t3.o
81+
# RUN: ld.lld -static --android-memtag-mode=sync %t1.o %t2.o %t3.o -o %t.static.so
82+
# RUN: llvm-readelf -s --section-headers --relocs --memtag %t.static.so | \
83+
# RUN: FileCheck %s --check-prefix=CHECK-STATIC
84+
# CHECK-STATIC-NOT: .memtag.globals.static
85+
# CHECK-STATIC-NOT: DT_AARCH64_MEMTAG_
86+
87+
# CHECK-STATIC: There are no relocations in this file
88+
# CHECK-STATIC: Memtag Dynamic Entries:
89+
# CHECK-STATIC-NEXT: < none found >
90+
91+
# RUN: llvm-objdump -tDz %t.static.so | FileCheck %s --check-prefix=CHECK-STATIC-SPECIAL-RELOCS
92+
# CHECK-STATIC-SPECIAL-RELOCS: [[#%x,HIDDEN_GLOBAL_ADDR:]] {{.*}} .bss {{0*}}10 hidden_global
93+
# CHECK-STATIC-SPECIAL-RELOCS: <pointer_to_hidden_global_end>:
94+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 12]]
95+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
96+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
97+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
98+
# CHECK-STATIC-SPECIAL-RELOCS: <pointer_past_hidden_global_end>:
99+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x{{0*}}[[#HIDDEN_GLOBAL_ADDR + 16]]
100+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
101+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
102+
# CHECK-STATIC-SPECIAL-RELOCS-NEXT: .word 0x00000000
80103

81104
# CHECK: Symbol table '.dynsym' contains
82105
# CHECK-DAG: [[#%x,GLOBAL:]] 32 OBJECT GLOBAL DEFAULT [[#]] global{{$}}

0 commit comments

Comments
 (0)