mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-29 06:10:09 +08:00
x86-64: shared libs improvement
This correctly resolves local references to global functions from shared libs to their PLT slot (instead of directly to the target symbol), so that interposition works. This is still not 100% conforming (executables don't export symbols that are also defined in linked shared libs, as they must), but normal shared lib situations work.
This commit is contained in:
parent
080ad7e62a
commit
0bd1282059
2
tcc.h
2
tcc.h
@ -522,7 +522,7 @@ typedef struct ASMOperand {
|
|||||||
|
|
||||||
struct sym_attr {
|
struct sym_attr {
|
||||||
unsigned long got_offset;
|
unsigned long got_offset;
|
||||||
unsigned char has_plt_entry:1;
|
unsigned long plt_offset;
|
||||||
#ifdef TCC_TARGET_ARM
|
#ifdef TCC_TARGET_ARM
|
||||||
unsigned char plt_thumb_stub:1;
|
unsigned char plt_thumb_stub:1;
|
||||||
#endif
|
#endif
|
||||||
|
70
tccelf.c
70
tccelf.c
@ -841,8 +841,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* fall through */
|
goto plt32pc32;
|
||||||
case R_X86_64_PLT32: {
|
|
||||||
|
case R_X86_64_PLT32:
|
||||||
|
/* We've put the PLT slot offset into r_addend when generating
|
||||||
|
it, and that's what we must use as relocation value (adjusted
|
||||||
|
by section offset of course). */
|
||||||
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
||||||
|
val = s1->plt->sh_addr + rel->r_addend;
|
||||||
|
/* fallthrough. */
|
||||||
|
|
||||||
|
plt32pc32:
|
||||||
|
{
|
||||||
long long diff;
|
long long diff;
|
||||||
diff = (long long)val - addr;
|
diff = (long long)val - addr;
|
||||||
if (diff <= -2147483647 || diff > 2147483647) {
|
if (diff <= -2147483647 || diff > 2147483647) {
|
||||||
@ -1011,13 +1021,14 @@ static void build_got(TCCState *s1)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* put a got entry corresponding to a symbol in symtab_section. 'size'
|
/* put a got or plt entry corresponding to a symbol in symtab_section. 'size'
|
||||||
and 'info' can be modifed if more precise info comes from the DLL */
|
and 'info' can be modifed if more precise info comes from the DLL.
|
||||||
static void put_got_entry(TCCState *s1,
|
Returns offset of GOT or PLT slot. */
|
||||||
int reloc_type, unsigned long size, int info,
|
static unsigned long put_got_entry(TCCState *s1,
|
||||||
int sym_index)
|
int reloc_type, unsigned long size, int info,
|
||||||
|
int sym_index)
|
||||||
{
|
{
|
||||||
int index, need_plt_entry, got_entry_present = 0;
|
int index, need_plt_entry;
|
||||||
const char *name;
|
const char *name;
|
||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
@ -1038,16 +1049,16 @@ static void put_got_entry(TCCState *s1,
|
|||||||
0;
|
0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* if a got entry already exists for that symbol, no need to add one */
|
/* If a got/plt entry already exists for that symbol, no need to add one */
|
||||||
if (sym_index < s1->nb_sym_attrs &&
|
if (sym_index < s1->nb_sym_attrs) {
|
||||||
s1->sym_attrs[sym_index].got_offset) {
|
if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset)
|
||||||
if (!need_plt_entry || s1->sym_attrs[sym_index].has_plt_entry)
|
return s1->sym_attrs[sym_index].plt_offset;
|
||||||
return;
|
else if (!need_plt_entry && s1->sym_attrs[sym_index].got_offset)
|
||||||
else
|
return s1->sym_attrs[sym_index].got_offset;
|
||||||
got_entry_present = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
symattr = alloc_sym_attr(s1, sym_index);
|
symattr = alloc_sym_attr(s1, sym_index);
|
||||||
|
|
||||||
/* Only store the GOT offset if it's not generated for the PLT entry. */
|
/* Only store the GOT offset if it's not generated for the PLT entry. */
|
||||||
if (!need_plt_entry)
|
if (!need_plt_entry)
|
||||||
symattr->got_offset = s1->got->data_offset;
|
symattr->got_offset = s1->got->data_offset;
|
||||||
@ -1090,6 +1101,7 @@ static void put_got_entry(TCCState *s1,
|
|||||||
via offset. The reloc entry is created below, so its
|
via offset. The reloc entry is created below, so its
|
||||||
offset is the current data_offset. */
|
offset is the current data_offset. */
|
||||||
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
|
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
|
||||||
|
symattr->plt_offset = plt->data_offset;
|
||||||
p = section_ptr_add(plt, 16);
|
p = section_ptr_add(plt, 16);
|
||||||
p[0] = 0xff; /* jmp *(got + x) */
|
p[0] = 0xff; /* jmp *(got + x) */
|
||||||
p[1] = modrm;
|
p[1] = modrm;
|
||||||
@ -1104,13 +1116,11 @@ static void put_got_entry(TCCState *s1,
|
|||||||
p[11] = 0xe9; /* jmp plt_start */
|
p[11] = 0xe9; /* jmp plt_start */
|
||||||
put32(p + 12, -(plt->data_offset));
|
put32(p + 12, -(plt->data_offset));
|
||||||
|
|
||||||
/* the symbol is modified so that it will be relocated to
|
/* If this was an UNDEF symbol set the offset in the
|
||||||
the PLT */
|
dynsymtab to the PLT slot, so that PC32 relocs to it
|
||||||
#if !defined(TCC_OUTPUT_DLL_WITH_PLT)
|
can be resolved. */
|
||||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
if (sym->st_shndx == SHN_UNDEF)
|
||||||
#endif
|
offset = plt->data_offset - 16;
|
||||||
offset = plt->data_offset - 16;
|
|
||||||
symattr->has_plt_entry = 1;
|
|
||||||
}
|
}
|
||||||
#elif defined(TCC_TARGET_ARM)
|
#elif defined(TCC_TARGET_ARM)
|
||||||
if (need_plt_entry) {
|
if (need_plt_entry) {
|
||||||
@ -1132,6 +1142,7 @@ static void put_got_entry(TCCState *s1,
|
|||||||
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
|
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
symattr->plt_offset = plt->data_offset;
|
||||||
if (symattr->plt_thumb_stub) {
|
if (symattr->plt_thumb_stub) {
|
||||||
p = section_ptr_add(plt, 20);
|
p = section_ptr_add(plt, 20);
|
||||||
put32(p, 0x4778); /* bx pc */
|
put32(p, 0x4778); /* bx pc */
|
||||||
@ -1148,7 +1159,6 @@ static void put_got_entry(TCCState *s1,
|
|||||||
the PLT */
|
the PLT */
|
||||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||||
offset = plt->data_offset - 16;
|
offset = plt->data_offset - 16;
|
||||||
symattr->has_plt_entry = 1;
|
|
||||||
}
|
}
|
||||||
#elif defined(TCC_TARGET_C67)
|
#elif defined(TCC_TARGET_C67)
|
||||||
tcc_error("C67 got not implemented");
|
tcc_error("C67 got not implemented");
|
||||||
@ -1167,6 +1177,10 @@ static void put_got_entry(TCCState *s1,
|
|||||||
/* And now create the GOT slot itself. */
|
/* And now create the GOT slot itself. */
|
||||||
ptr = section_ptr_add(s1->got, PTR_SIZE);
|
ptr = section_ptr_add(s1->got, PTR_SIZE);
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
|
if (need_plt_entry)
|
||||||
|
return symattr->plt_offset;
|
||||||
|
else
|
||||||
|
return symattr->got_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* build GOT and PLT entries */
|
/* build GOT and PLT entries */
|
||||||
@ -1281,6 +1295,7 @@ ST_FUNC void build_got_entries(TCCState *s1)
|
|||||||
build_got(s1);
|
build_got(s1);
|
||||||
if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL ||
|
if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL ||
|
||||||
type == R_X86_64_PLT32) {
|
type == R_X86_64_PLT32) {
|
||||||
|
unsigned long ofs;
|
||||||
sym_index = ELFW(R_SYM)(rel->r_info);
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
/* look at the symbol got offset. If none, then add one */
|
/* look at the symbol got offset. If none, then add one */
|
||||||
@ -1288,8 +1303,13 @@ ST_FUNC void build_got_entries(TCCState *s1)
|
|||||||
reloc_type = R_X86_64_GLOB_DAT;
|
reloc_type = R_X86_64_GLOB_DAT;
|
||||||
else
|
else
|
||||||
reloc_type = R_X86_64_JUMP_SLOT;
|
reloc_type = R_X86_64_JUMP_SLOT;
|
||||||
put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
|
ofs = put_got_entry(s1, reloc_type, sym->st_size,
|
||||||
sym_index);
|
sym->st_info, sym_index);
|
||||||
|
if (type == R_X86_64_PLT32
|
||||||
|
&& s1->output_type != TCC_OUTPUT_MEMORY)
|
||||||
|
/* We store the place of the generated PLT slot
|
||||||
|
in our addend. */
|
||||||
|
rel->r_addend += ofs;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
|
Loading…
Reference in New Issue
Block a user