forked from OSchip/llvm-project
67 lines
2.3 KiB
Plaintext
67 lines
2.3 KiB
Plaintext
# REQUIRES: x86
|
|
|
|
# LLD used to crash when linking against a DSO with an undefined STB_LOCAL
|
|
# symbol in the global part of the dynamic symbol table (i.e. an STB_LOCAL
|
|
# symbol with an index >= the sh_info of the dynamic symbol table section). Such
|
|
# a DSO is very broken, because local symbols should precede all global symbols
|
|
# in the symbol table, and because having a symbol that's both undefined and
|
|
# STB_LOCAL is a nonsensical combination. Nevertheless, we should warn on such
|
|
# input files instead of crashing.
|
|
|
|
# We've found actual broken DSOs of this sort in the wild, but for this test, we
|
|
# created a reduced broken input file. There are no tools capable of producing a
|
|
# broken DSO of this nature, so instead we created a valid DSO with an undefined
|
|
# global symbol in the dynamic symbol table and then manually edited the binary
|
|
# to make that symbol local. The valid DSO was created as follows:
|
|
|
|
```
|
|
% cat undef.s
|
|
.hidden bar
|
|
bar:
|
|
movq foo@GOT, %rax
|
|
|
|
% llvm-mc -triple=x86_64-linux-gnu -filetype=obj -o undef.o undef.s
|
|
% ld.lld --no-rosegment -shared -o undefined-local-symbol-in-dso.so undef.o
|
|
% strip undef.so
|
|
```
|
|
|
|
# (--no-rosegment and stripping are unnecessary; they just produce a smaller
|
|
# binary)
|
|
|
|
# This DSO should only have a single dynamic symbol table entry for foo, and
|
|
# then we can use a small C program to modify that symbol table entry to be
|
|
# STB_LOCAL instead of STB_GLOBAL.
|
|
|
|
```
|
|
#include <elf.h>
|
|
#include <stdio.h>
|
|
|
|
int main(int argc, char *argv[]) {
|
|
FILE *F = fopen(argv[1], "rb+");
|
|
|
|
Elf64_Ehdr Ehdr;
|
|
fread(&Ehdr, sizeof(Ehdr), 1, F);
|
|
fseek(F, Ehdr.e_shoff, SEEK_SET);
|
|
|
|
Elf64_Shdr Shdr;
|
|
do {
|
|
fread(&Shdr, sizeof(Shdr), 1, F);
|
|
} while (Shdr.sh_type != SHT_DYNSYM);
|
|
|
|
Elf64_Sym Sym;
|
|
fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET);
|
|
fread(&Sym, sizeof(Sym), 1, F);
|
|
Sym.st_info = STB_LOCAL << 4 | ELF64_ST_TYPE(Sym.st_info);
|
|
fseek(F, Shdr.sh_offset + sizeof(Elf64_Sym), SEEK_SET);
|
|
fwrite(&Sym, sizeof(Sym), 1, F);
|
|
fclose(F);
|
|
}
|
|
```
|
|
|
|
# (the C program just takes its input DSO and modifies the binding of the first
|
|
# dynamic symbol table entry to be STB_LOCAL instead of STB_GLOBAL)
|
|
|
|
# RUN: ld.lld %p/Inputs/undefined-local-symbol-in-dso.so -o %t 2>&1 | \
|
|
# RUN: FileCheck -check-prefix=WARN %s
|
|
# WARN: found local symbol 'foo' in global part of symbol table in file {{.*}}undefined-local-symbol-in-dso.so
|