x86-64: Add basic shared lib support
Initial support for shared libraries on x86-64.
This commit is contained in:
parent
5a5fee867a
commit
080ad7e62a
2 changed files with 41 additions and 37 deletions
76
tccelf.c
76
tccelf.c
|
@ -802,9 +802,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
||||||
#elif defined(TCC_TARGET_X86_64)
|
#elif defined(TCC_TARGET_X86_64)
|
||||||
case R_X86_64_64:
|
case R_X86_64_64:
|
||||||
if (s1->output_type == TCC_OUTPUT_DLL) {
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
||||||
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
|
esym_index = s1->symtab_to_dynsym[sym_index];
|
||||||
qrel->r_addend = *(long long *)ptr + val;
|
qrel->r_offset = rel->r_offset;
|
||||||
qrel++;
|
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;
|
*(long long *)ptr += val;
|
||||||
break;
|
break;
|
||||||
|
@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1,
|
||||||
ElfW(Sym) *sym;
|
ElfW(Sym) *sym;
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
int *ptr;
|
int *ptr;
|
||||||
|
struct sym_attr *symattr;
|
||||||
|
|
||||||
if (!s1->got)
|
if (!s1->got)
|
||||||
build_got(s1);
|
build_got(s1);
|
||||||
|
@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1,
|
||||||
got_entry_present = 1;
|
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) {
|
if (s1->dynsym) {
|
||||||
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||||
|
@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1,
|
||||||
Section *plt;
|
Section *plt;
|
||||||
uint8_t *p;
|
uint8_t *p;
|
||||||
int modrm;
|
int modrm;
|
||||||
|
unsigned long relofs;
|
||||||
|
|
||||||
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
|
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
|
||||||
modrm = 0x25;
|
modrm = 0x25;
|
||||||
|
@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1,
|
||||||
put32(p + 8, PTR_SIZE * 2);
|
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 = section_ptr_add(plt, 16);
|
||||||
p[0] = 0xff; /* jmp *(got + x) */
|
p[0] = 0xff; /* jmp *(got + x) */
|
||||||
p[1] = modrm;
|
p[1] = modrm;
|
||||||
put32(p + 2, s1->got->data_offset);
|
put32(p + 2, s1->got->data_offset);
|
||||||
p[6] = 0x68; /* push $xxx */
|
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 */
|
p[11] = 0xe9; /* jmp plt_start */
|
||||||
put32(p + 12, -(plt->data_offset));
|
put32(p + 12, -(plt->data_offset));
|
||||||
|
|
||||||
|
@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1,
|
||||||
if (s1->output_type == TCC_OUTPUT_EXE)
|
if (s1->output_type == TCC_OUTPUT_EXE)
|
||||||
#endif
|
#endif
|
||||||
offset = plt->data_offset - 16;
|
offset = plt->data_offset - 16;
|
||||||
s1->sym_attrs[sym_index].has_plt_entry = 1;
|
symattr->has_plt_entry = 1;
|
||||||
}
|
}
|
||||||
#elif defined(TCC_TARGET_ARM)
|
#elif defined(TCC_TARGET_ARM)
|
||||||
if (need_plt_entry) {
|
if (need_plt_entry) {
|
||||||
|
@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1,
|
||||||
put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
|
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);
|
p = section_ptr_add(plt, 20);
|
||||||
put32(p, 0x4778); /* bx pc */
|
put32(p, 0x4778); /* bx pc */
|
||||||
put32(p+2, 0x46c0); /* nop */
|
put32(p+2, 0x46c0); /* nop */
|
||||||
|
@ -1125,27 +1148,23 @@ 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;
|
||||||
s1->sym_attrs[sym_index].has_plt_entry = 1;
|
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");
|
||||||
#else
|
#else
|
||||||
#error unsupported CPU
|
#error unsupported CPU
|
||||||
#endif
|
#endif
|
||||||
|
/* XXX This might generate multiple syms for name. */
|
||||||
index = put_elf_sym(s1->dynsym, offset,
|
index = put_elf_sym(s1->dynsym, offset,
|
||||||
size, info, 0, sym->st_shndx, name);
|
size, info, 0, sym->st_shndx, name);
|
||||||
if (got_entry_present) {
|
/* Create the relocation (it's against the GOT for PLT
|
||||||
put_elf_reloc(s1->dynsym, s1->got,
|
and GOT relocs). */
|
||||||
s1->sym_attrs[sym_index].got_offset,
|
|
||||||
reloc_type, index);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* put a got entry */
|
|
||||||
put_elf_reloc(s1->dynsym, s1->got,
|
put_elf_reloc(s1->dynsym, s1->got,
|
||||||
s1->got->data_offset,
|
s1->got->data_offset,
|
||||||
reloc_type, index);
|
reloc_type, index);
|
||||||
}
|
}
|
||||||
|
/* 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;
|
||||||
}
|
}
|
||||||
|
@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1)
|
||||||
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
|
s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms);
|
||||||
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
||||||
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
||||||
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
|
name = (char *) symtab_section->link->data + sym->st_name;
|
||||||
int type = ELFW(ST_TYPE)(sym->st_info);
|
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
||||||
if ((type == STT_FUNC || type == STT_GNU_IFUNC)
|
sym->st_info, 0, sym->st_shndx, name);
|
||||||
&& sym->st_shndx == SHN_UNDEF) {
|
index = sym - (ElfW(Sym) *) symtab_section->data;
|
||||||
int visibility = ELFW(ST_BIND)(sym->st_info);
|
s1->symtab_to_dynsym[index] = dynindex;
|
||||||
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);
|
|
||||||
index = sym - (ElfW(Sym) *) symtab_section->data;
|
|
||||||
s1->symtab_to_dynsym[index] = dynindex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp)
|
||||||
if (vtop->r & VT_SYM) {
|
if (vtop->r & VT_SYM) {
|
||||||
/* relocation case */
|
/* relocation case */
|
||||||
greloc(cur_text_section, vtop->sym,
|
greloc(cur_text_section, vtop->sym,
|
||||||
ind + 1, R_X86_64_PC32);
|
ind + 1, R_X86_64_PLT32);
|
||||||
} else {
|
} else {
|
||||||
/* put an empty PC32 relocation */
|
/* put an empty PC32 relocation */
|
||||||
put_elf_reloc(symtab_section, cur_text_section,
|
put_elf_reloc(symtab_section, cur_text_section,
|
||||||
|
|
Loading…
Reference in a new issue