From d63ec6f20dc7e29e266589458ea90fb56f8c86ea Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Thu, 4 Feb 2010 23:08:01 +0330 Subject: [PATCH] fill got table for static linking --- libtcc.c | 9 +++++++++ tcc.h | 1 + tccelf.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/libtcc.c b/libtcc.c index 2f23fe62..bea52de1 100644 --- a/libtcc.c +++ b/libtcc.c @@ -372,6 +372,15 @@ ST_FUNC void *section_ptr_add(Section *sec, unsigned long size) return sec->data + offset; } +/* reserve at least 'size' bytes from section start */ +ST_FUNC void section_reserve(Section *sec, unsigned long size) +{ + if (size > sec->data_allocated) + section_realloc(sec, size); + if (size > sec->data_offset) + sec->data_offset = size; +} + /* return a reference to a section, and create it if it does not exists */ ST_FUNC Section *find_section(TCCState *s1, const char *name) diff --git a/tcc.h b/tcc.h index ef0bb785..0170f11c 100644 --- a/tcc.h +++ b/tcc.h @@ -900,6 +900,7 @@ ST_FUNC void add_char(CString *cstr, int c); ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags); ST_FUNC void section_realloc(Section *sec, unsigned long new_size); ST_FUNC void *section_ptr_add(Section *sec, unsigned long size); +ST_FUNC void section_reserve(Section *sec, unsigned long size); ST_FUNC Section *find_section(TCCState *s1, const char *name); ST_FUNC void put_extern_sym2(Sym *sym, Section *section, unsigned long value, unsigned long size, int can_add_underscore); diff --git a/tccelf.c b/tccelf.c index f262ac5d..29b9c8c5 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1365,6 +1365,48 @@ void patch_dynsym_undef(TCCState *s1, Section *s) #define EXTRA_RELITEMS 9 #endif +ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) +{ + int sym_index = ELFW(R_SYM) (rel->r_info); + ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; + unsigned long offset; + + if (sym_index >= s1->nb_got_offsets) + return; + offset = s1->got_offsets[sym_index]; + section_reserve(s1->got, offset + PTR_SIZE); + /* only works for x86-64 */ + put32(s1->got->data + offset, sym->st_value >> 32); + put32(s1->got->data + offset, sym->st_value & 0xffffffff); +} + +ST_FUNC void fill_got(TCCState *s1) +{ + Section *s; + ElfW_Rel *rel, *rel_end; + int i; + + for(i = 1; i < s1->nb_sections; i++) { + s = s1->sections[i]; + if (s->sh_type != SHT_RELX) + continue; + /* no need to handle got relocations */ + if (s->link != symtab_section) + continue; + rel_end = (ElfW_Rel *) (s->data + s->data_offset); + for(rel = (ElfW_Rel *) s->data; rel < rel_end; rel++) { + switch (ELFW(R_TYPE) (rel->r_info)) { + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + case R_X86_64_PLT32: + fill_got_entry(s1, rel); + break; + } + } + } +} + + /* output an ELF file */ /* XXX: suppress unneeded sections */ static int elf_output_file(TCCState *s1, const char *filename) @@ -1985,6 +2027,8 @@ static int elf_output_file(TCCState *s1, const char *filename) else ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ } + if (file_type == TCC_OUTPUT_EXE && s1->static_link) + fill_got(s1); /* write elf file */ if (file_type == TCC_OUTPUT_OBJ) -- 2.11.4.GIT