tccelf: use plt-reloc instead of relocplt

This commit is contained in:
grischka 2021-01-28 14:20:05 +01:00
parent e4f151c4cd
commit 02795106e1
10 changed files with 108 additions and 163 deletions

View File

@ -167,15 +167,11 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
if (s1->plt->reloc) {
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write32le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr);
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write32le(p + rel->r_offset, s1->plt->sh_addr);
}
}
}

View File

@ -155,15 +155,11 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
if (s1->plt->reloc) {
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr);
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write64le(p + rel->r_offset, s1->plt->sh_addr);
}
}
}

View File

@ -121,7 +121,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* 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->relocplt ? s1->got->relocplt->data_offset : 0;
relofs = s1->plt->reloc ? s1->plt->reloc->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16);
@ -157,16 +157,12 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
if (s1->plt->reloc) {
ElfW_Rel *rel;
int x = s1->plt->sh_addr + 16 + 6;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write32le(p + rel->r_offset, mem ? sym->st_value : x);
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write32le(p + rel->r_offset, x);
x += 16;
}
}

View File

@ -154,15 +154,11 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
if (s1->plt->reloc) {
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value + rel->r_addend : s1->plt->sh_addr);
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write64le(p + rel->r_offset, s1->plt->sh_addr);
}
}
}

5
tcc.h
View File

@ -423,7 +423,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ElfW_Rel ElfW(Rela)
# define SHT_RELX SHT_RELA
# define REL_SECTION_FMT ".rela%s"
# define RELPLT_SECTION_FMT ".rela.plt"
#else
# define ELFCLASSW ELFCLASS32
# define ElfW(type) Elf##32##_##type
@ -431,7 +430,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ElfW_Rel ElfW(Rel)
# define SHT_RELX SHT_REL
# define REL_SECTION_FMT ".rel%s"
# define RELPLT_SECTION_FMT ".rel.plt"
#endif
/* target address type */
#define addr_t ElfW(Addr)
@ -593,7 +591,6 @@ typedef struct Section {
struct Section *reloc; /* corresponding section for relocation, if any */
struct Section *hash; /* hash table for symbols */
struct Section *prev; /* previous section on section stack */
struct Section *relocplt;/* reloc with JMP_SLOTs */
char name[1]; /* section name */
} Section;
@ -1588,7 +1585,7 @@ ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value);
ST_FUNC void resolve_common_syms(TCCState *s1);
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
ST_FUNC void relocate_section(TCCState *s1, Section *s);
ST_FUNC void relocate_sections(TCCState *s1);
ST_FUNC ssize_t full_read(int fd, void *buf, size_t count);
ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size);

180
tccelf.c
View File

@ -737,25 +737,18 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
char buf[256];
Section *sr;
ElfW_Rel *rel;
int jmp_slot = type == R_JMP_SLOT;
sr = jmp_slot ? s->relocplt : s->reloc;
sr = s->reloc;
if (!sr) {
/* if no relocation section, create it */
if (jmp_slot)
snprintf(buf, sizeof(buf), RELPLT_SECTION_FMT);
else
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
/* if the symtab is allocated, then we consider the relocation
are also */
sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
if (jmp_slot)
s->relocplt = sr;
else
s->reloc = sr;
s->reloc = sr;
}
rel = section_ptr_add(sr, sizeof(ElfW_Rel));
rel->r_offset = offset;
@ -957,9 +950,8 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
/* relocate a given section (CPU dependent) by applying the relocations
in the associated relocation section */
ST_FUNC void relocate_section(TCCState *s1, Section *s)
static void relocate_section(TCCState *s1, Section *s, Section *sr)
{
Section *sr = s->reloc;
ElfW_Rel *rel;
ElfW(Sym) *sym;
int type, sym_index;
@ -967,7 +959,6 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
addr_t tgt, addr;
qrel = (ElfW_Rel *)sr->data;
for_each_elem(sr, 0, rel, ElfW_Rel) {
ptr = s->data + rel->r_offset;
sym_index = ELFW(R_SYM)(rel->r_info);
@ -980,6 +971,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
addr = s->sh_addr + rel->r_offset;
relocate(s1, rel, type, ptr, addr, tgt);
}
#ifndef ELF_OBJ_ONLY
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC) {
sr->link = s1->dynsym;
@ -991,20 +983,37 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
sr->data_offset = sr->sh_size = r;
}
}
#endif
}
/* relocate all sections */
ST_FUNC void relocate_sections(TCCState *s1)
{
int i;
Section *s, *sr;
for (i = 1; i < s1->nb_sections; ++i) {
sr = s1->sections[i];
if (sr->sh_type != SHT_RELX)
continue;
s = s1->sections[sr->sh_info];
if (s != s1->got
|| s1->static_link
|| s1->output_type == TCC_OUTPUT_MEMORY) {
relocate_section(s1, s, sr);
}
#ifndef ELF_OBJ_ONLY
if (sr->sh_flags & SHF_ALLOC) {
ElfW_Rel *rel;
/* relocate relocation table in 'sr' */
for_each_elem(sr, 0, rel, ElfW_Rel)
rel->r_offset += s->sh_addr;
}
#endif
}
}
#ifndef ELF_OBJ_ONLY
/* relocate relocation table in 'sr' */
static void relocate_rel(TCCState *s1, Section *sr)
{
Section *s;
ElfW_Rel *rel;
s = s1->sections[sr->sh_info];
for_each_elem(sr, 0, rel, ElfW_Rel)
rel->r_offset += s->sh_addr;
}
/* count the number of dynamic relocations so that we can reserve
their space */
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
@ -1099,6 +1108,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
unsigned got_offset;
char plt_name[100];
int len;
Section *s_rel;
need_plt_entry = (dyn_reloc_type == R_JMP_SLOT);
attr = get_sym_attr(s1, sym_index, 1);
@ -1109,6 +1119,15 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
if (need_plt_entry ? attr->plt_offset : attr->got_offset)
return attr;
s_rel = s1->got;
if (need_plt_entry) {
if (!s1->plt) {
s1->plt = new_section(s1, ".plt", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
s1->plt->sh_entsize = 4;
}
s_rel = s1->plt;
}
/* create the GOT entry */
got_offset = s1->got->data_offset;
section_ptr_add(s1->got, PTR_SIZE);
@ -1123,6 +1142,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
name = (char *) symtab_section->link->data + sym->st_name;
//printf("sym %d %s\n", need_plt_entry, name);
if (s1->dynsym) {
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
@ -1147,7 +1167,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value,
sym->st_size, sym->st_info, 0,
sym->st_shndx, name);
put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
put_elf_reloc(s1->dynsym, s_rel, got_offset, dyn_reloc_type,
attr->dyn_index);
}
} else {
@ -1156,12 +1176,6 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
}
if (need_plt_entry) {
if (!s1->plt) {
s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
SHF_ALLOC | SHF_EXECINSTR);
s1->plt->sh_entsize = 4;
}
attr->plt_offset = create_plt_entry(s1, got_offset, attr);
/* create a symbol 'sym@plt' for the PLT jump vector */
@ -1172,7 +1186,6 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
strcpy(plt_name + len, "@plt");
attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size,
ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name);
} else {
attr->got_offset = got_offset;
}
@ -1181,14 +1194,18 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
}
/* build GOT and PLT entries */
static void build_got_entries_pass(TCCState *s1, int pass)
/* Two passes because R_JMP_SLOT should become first. Some targets
(arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */
ST_FUNC void build_got_entries(TCCState *s1)
{
Section *s;
ElfW_Rel *rel;
ElfW(Sym) *sym;
int i, type, gotplt_entry, reloc_type, sym_index;
struct sym_attr *attr;
int pass = 0;
redo:
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_type != SHT_RELX)
@ -1252,7 +1269,7 @@ static void build_got_entries_pass(TCCState *s1, int pass)
(ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
ELFW(ST_BIND)(sym->st_info) == STB_LOCAL ||
s1->output_type == TCC_OUTPUT_EXE)) {
if (pass == 0)
if (pass != 0)
continue;
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
continue;
@ -1261,16 +1278,17 @@ static void build_got_entries_pass(TCCState *s1, int pass)
reloc_type = code_reloc(type);
if (reloc_type == -1)
tcc_error ("Unknown relocation type: %d", type);
else if (reloc_type != 0) {
jmp_slot:
if (reloc_type != 0) {
jmp_slot:
if (pass != 0)
continue;
reloc_type = R_JMP_SLOT;
} else
} else {
if (pass != 1)
continue;
reloc_type = R_GLOB_DAT;
if ((pass == 0 && reloc_type == R_GLOB_DAT) ||
(pass == 1 && reloc_type == R_JMP_SLOT))
continue;
}
if (!s1->got)
build_got(s1);
@ -1284,16 +1302,13 @@ static void build_got_entries_pass(TCCState *s1, int pass)
rel->r_info = ELFW(R_INFO)(attr->plt_sym, type);
}
}
}
if (++pass < 2)
goto redo;
ST_FUNC void build_got_entries(TCCState *s1)
{
int i;
/* .rel.plt refers to .got actually */
if (s1->plt && s1->plt->reloc)
s1->plt->reloc->sh_info = s1->got->sh_num;
/* Two passes because R_JMP_SLOT should become first.
Some targets (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */
for (i = 0; i < 2; i++)
build_got_entries_pass(s1, i);
}
#endif
@ -1931,8 +1946,6 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
roinf->sh_offset = roinf->sh_addr = roinf->sh_size = 0;
for(j = 0; j < phfill; j++) {
Section *relocplt = s1->got ? s1->got->relocplt : NULL;
ph->p_type = j == 2 ? PT_TLS : PT_LOAD;
if (j == 0)
ph->p_flags = PF_R | PF_X;
@ -1973,10 +1986,13 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr,
if (k != 1)
continue;
} else if (s->sh_type == SHT_RELX) {
if (k != 2 && s != relocplt)
continue;
else if (k != 3 && s == relocplt)
continue;
if (s1->plt && s == s1->plt->reloc) {
if (k != 3)
continue;
} else {
if (k != 2)
continue;
}
} else if (s->sh_type == SHT_NOBITS) {
if (k != 6)
continue;
@ -2155,10 +2171,10 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_RELA, dyninf->rel_addr);
put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
if (s1->got && s1->got->relocplt) {
if (s1->plt && s1->plt->reloc) {
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset);
put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset);
put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr);
put_dt(dynamic, DT_PLTREL, DT_RELA);
}
put_dt(dynamic, DT_RELACOUNT, 0);
@ -2166,10 +2182,10 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_REL, dyninf->rel_addr);
put_dt(dynamic, DT_RELSZ, dyninf->rel_size);
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
if (s1->got && s1->got->relocplt) {
if (s1->plt && s1->plt->reloc) {
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset);
put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, s1->plt->reloc->data_offset);
put_dt(dynamic, DT_JMPREL, s1->plt->reloc->sh_addr);
put_dt(dynamic, DT_PLTREL, DT_REL);
}
put_dt(dynamic, DT_RELCOUNT, 0);
@ -2208,38 +2224,6 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_NULL, 0);
}
/* Relocate remaining sections and symbols (that is those not related to
dynamic linking) */
static int final_sections_reloc(TCCState *s1)
{
int i;
Section *s;
relocate_syms(s1, s1->symtab, 0);
if (s1->nb_errors != 0)
return -1;
/* relocate sections */
/* XXX: ignore sections with allocated relocations ? */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->reloc && (s != s1->got || s1->static_link))
relocate_section(s1, s);
}
/* relocate relocation entries if the relocation tables are
allocated in the executable */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if ((s->sh_flags & SHF_ALLOC) &&
s->sh_type == SHT_RELX) {
relocate_rel(s1, s);
}
}
return 0;
}
/* Remove gaps between RELX sections.
These gaps are a result of final_sections_reloc. Here some relocs are removed.
The gaps are then filled with 0 in tcc_output_elf. The 0 is intepreted as
@ -2250,7 +2234,7 @@ static void update_reloc_sections(TCCState *s1, struct dyn_inf *dyninf)
int i;
unsigned long file_offset = 0;
Section *s;
Section *relocplt = s1->got ? s1->got->relocplt : NULL;
Section *relocplt = s1->plt ? s1->plt->reloc : NULL;
/* dynamic relocation table information, for .dynamic section */
dyninf->rel_addr = dyninf->rel_size = 0;
@ -2724,9 +2708,11 @@ static int elf_output_file(TCCState *s1, const char *filename)
/* if building executable or DLL, then relocate each section
except the GOT which is already relocated */
ret = final_sections_reloc(s1);
if (ret)
relocate_syms(s1, s1->symtab, 0);
ret = -1;
if (s1->nb_errors != 0)
goto the_end;
relocate_sections(s1);
if (dynamic) {
update_reloc_sections (s1, &dyninf);
dynamic->data_offset = dyninf.data_offset;

View File

@ -809,22 +809,14 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
check_relocs(s1, &mo);
ret = check_symbols(s1, &mo);
if (!ret) {
int i;
Section *s;
collect_sections(s1, &mo);
relocate_syms(s1, s1->symtab, 0);
mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1)
- get_segment(&mo, 1)->vmaddr;
if (s1->nb_errors)
goto do_ret;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->reloc)
relocate_section(s1, s);
}
relocate_sections(s1);
convert_symbols(s1, &mo);
macho_write(s1, &mo, fp);
}

12
tccpe.c
View File

@ -982,7 +982,7 @@ static void pe_build_exports(struct pe_info *pe)
for (ord = 0; ord < sym_count; ++ord)
{
p = sorted[ord], sym_index = p->index, name = p->name;
/* insert actual address later in relocate_section() */
/* insert actual address later in relocate_sections() */
put_elf_reloc(symtab_section, pe->thunk,
func_o, R_XXX_RELATIVE, sym_index);
*(DWORD*)(pe->thunk->data + name_o)
@ -1937,7 +1937,7 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
}
}
/* need this for 'tccelf.c:relocate_section()' */
/* need this for 'tccelf.c:relocate_sections()' */
if (TCC_OUTPUT_DLL == s1->output_type)
s1->output_type = TCC_OUTPUT_EXE;
if (TCC_OUTPUT_MEMORY == s1->output_type)
@ -1996,7 +1996,6 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
{
int ret;
struct pe_info pe;
int i;
memset(&pe, 0, sizeof pe);
pe.filename = filename;
@ -2018,12 +2017,7 @@ ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
s1->pe_imagebase = pe.imagebase;
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
if (s->reloc) {
relocate_section(s1, s);
}
}
relocate_sections(s1);
pe.start_addr = (DWORD)
(get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
if (s1->nb_errors)

View File

@ -277,15 +277,11 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr, addr_t ptr_diff)
s1->pe_imagebase = mem;
#endif
/* relocate each section */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->reloc)
relocate_section(s1, s);
}
#if !defined(TCC_TARGET_PE) || defined(TCC_TARGET_MACHO)
/* relocate sections */
#ifndef TCC_TARGET_PE
relocate_plt(s1);
#endif
relocate_sections(s1);
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];

View File

@ -131,7 +131,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* 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->relocplt ? s1->got->relocplt->data_offset : 0;
relofs = s1->plt->reloc ? s1->plt->reloc->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16);
@ -169,16 +169,12 @@ ST_FUNC void relocate_plt(TCCState *s1)
}
}
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
if (s1->plt->reloc) {
ElfW_Rel *rel;
int x = s1->plt->sh_addr + 16 + 6;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value : x);
for_each_elem(s1->plt->reloc, 0, rel, ElfW_Rel) {
write64le(p + rel->r_offset, x);
x += 16;
}
}