x86-64: Add basic shared lib support

Initial support for shared libraries on x86-64.
This commit is contained in:
Michael Matz 2014-03-31 03:45:35 +02:00
parent 5a5fee867a
commit 080ad7e62a
2 changed files with 41 additions and 37 deletions

View file

@ -802,10 +802,19 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
#elif defined(TCC_TARGET_X86_64)
case R_X86_64_64:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = s1->symtab_to_dynsym[sym_index];
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
qrel->r_addend = rel->r_addend;
qrel++;
break;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = *(long long *)ptr + val;
qrel++;
}
}
*(long long *)ptr += val;
break;
case R_X86_64_32:
@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1,
ElfW(Sym) *sym;
unsigned long offset;
int *ptr;
struct sym_attr *symattr;
if (!s1->got)
build_got(s1);
@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1,
got_entry_present = 1;
}
alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_offset;
symattr = alloc_sym_attr(s1, sym_index);
/* Only store the GOT offset if it's not generated for the PLT entry. */
if (!need_plt_entry)
symattr->got_offset = s1->got->data_offset;
if (s1->dynsym) {
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1,
Section *plt;
uint8_t *p;
int modrm;
unsigned long relofs;
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
modrm = 0x25;
@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1,
put32(p + 8, PTR_SIZE * 2);
}
/* The PLT slot refers to the relocation entry it needs
via offset. The reloc entry is created below, so its
offset is the current data_offset. */
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0;
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
put32(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */
put32(p + 7, (plt->data_offset - 32) >> 1);
#ifdef TCC_TARGET_X86_64
/* On x86-64, the relocation is referred to by _index_. */
put32(p + 7, relofs / sizeof (ElfW_Rel));
#else
put32(p + 7, relofs);
#endif
p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset));
@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1,
if (s1->output_type == TCC_OUTPUT_EXE)
#endif
offset = plt->data_offset - 16;
s1->sym_attrs[sym_index].has_plt_entry = 1;
symattr->has_plt_entry = 1;
}
#elif defined(TCC_TARGET_ARM)
if (need_plt_entry) {
@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1,
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
}
if (s1->sym_attrs[sym_index].plt_thumb_stub) {
if (symattr->plt_thumb_stub) {
p = section_ptr_add(plt, 20);
put32(p, 0x4778); /* bx pc */
put32(p+2, 0x46c0); /* nop */
@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1,
the PLT */
if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
s1->sym_attrs[sym_index].has_plt_entry = 1;
symattr->has_plt_entry = 1;
}
#elif defined(TCC_TARGET_C67)
tcc_error("C67 got not implemented");
#else
#error unsupported CPU
#endif
/* XXX This might generate multiple syms for name. */
index = put_elf_sym(s1->dynsym, offset,
size, info, 0, sym->st_shndx, name);
if (got_entry_present) {
put_elf_reloc(s1->dynsym, s1->got,
s1->sym_attrs[sym_index].got_offset,
reloc_type, index);
return;
}
/* put a got entry */
/* Create the relocation (it's against the GOT for PLT
and GOT relocs). */
put_elf_reloc(s1->dynsym, s1->got,
s1->got->data_offset,
reloc_type, index);
}
/* And now create the GOT slot itself. */
ptr = section_ptr_add(s1->got, PTR_SIZE);
*ptr = 0;
}
@ -1697,20 +1716,6 @@ static void export_global_syms(TCCState *s1)
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
int type = ELFW(ST_TYPE)(sym->st_info);
if ((type == STT_FUNC || type == STT_GNU_IFUNC)
&& sym->st_shndx == SHN_UNDEF) {
int visibility = ELFW(ST_BIND)(sym->st_info);
put_got_entry(s1, R_JMP_SLOT, sym->st_size,
ELFW(ST_INFO)(visibility, STT_FUNC),
sym - (ElfW(Sym) *) symtab_section->data);
} else if (type == STT_OBJECT) {
put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info,
sym - (ElfW(Sym) *) symtab_section->data);
} else
#endif
{
name = (char *) symtab_section->link->data + sym->st_name;
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
sym->st_info, 0, sym->st_shndx, name);
@ -1718,7 +1723,6 @@ static void export_global_syms(TCCState *s1)
s1->symtab_to_dynsym[index] = dynindex;
}
}
}
}
/* relocate the PLT: compute addresses and offsets in the PLT now that final

View file

@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp)
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
ind + 1, R_X86_64_PC32);
ind + 1, R_X86_64_PLT32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,