📄 tccelf.c
字号:
/* relocate symbol table, resolve undefined symbols if do_resolve is true and output error if undefined symbol. */static void relocate_syms(TCCState *s1, int do_resolve){ Elf32_Sym *sym, *esym, *sym_end; int sym_bind, sh_num, sym_index; const char *name; unsigned long addr; sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); for(sym = (Elf32_Sym *)symtab_section->data + 1; sym < sym_end; sym++) { sh_num = sym->st_shndx; if (sh_num == SHN_UNDEF) { name = strtab_section->data + sym->st_name; if (do_resolve) { name = symtab_section->link->data + sym->st_name; addr = (unsigned long)resolve_sym(name); if (addr) { sym->st_value = addr; goto found; } } else if (s1->dynsym) { /* if dynamic symbol exist, then use it */ sym_index = find_elf_sym(s1->dynsym, name); if (sym_index) { esym = &((Elf32_Sym *)s1->dynsym->data)[sym_index]; sym->st_value = esym->st_value; goto found; } } /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ if (!strcmp(name, "_fp_hw")) goto found; /* only weak symbols are accepted to be undefined. Their value is zero */ sym_bind = ELF32_ST_BIND(sym->st_info); if (sym_bind == STB_WEAK) { sym->st_value = 0; } else { error_noabort("undefined symbol '%s'", name); } } else if (sh_num < SHN_LORESERVE) { /* add section base */ sym->st_value += s1->sections[sym->st_shndx]->sh_addr; } found: ; }}/* relocate a given section (CPU dependent) */static void relocate_section(TCCState *s1, Section *s){ Section *sr; Elf32_Rel *rel, *rel_end, *qrel; Elf32_Sym *sym; int type, sym_index, esym_index; unsigned char *ptr; unsigned long val, addr; sr = s->reloc; rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); qrel = (Elf32_Rel *)sr->data; for(rel = qrel; rel < rel_end; rel++) { ptr = s->data + rel->r_offset; sym_index = ELF32_R_SYM(rel->r_info); sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; val = sym->st_value; type = ELF32_R_TYPE(rel->r_info); addr = s->sh_addr + rel->r_offset; /* CPU specific */ switch(type) { case R_386_32: 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 = ELF32_R_INFO(esym_index, R_386_32); qrel++; break; } else { qrel->r_info = ELF32_R_INFO(0, R_386_RELATIVE); qrel++; } } *(int *)ptr += val; break; case R_386_PC32: if (s1->output_type == TCC_OUTPUT_DLL) { /* DLL relocation */ esym_index = s1->symtab_to_dynsym[sym_index]; if (esym_index) { qrel->r_offset = rel->r_offset; qrel->r_info = ELF32_R_INFO(esym_index, R_386_PC32); qrel++; break; } } *(int *)ptr += val - addr; break; case R_386_PLT32: *(int *)ptr += val - addr; break; case R_386_GLOB_DAT: case R_386_JMP_SLOT: *(int *)ptr = val; break; case R_386_GOTPC: *(int *)ptr += s1->got->sh_addr - addr; break; case R_386_GOTOFF: *(int *)ptr += val - s1->got->sh_addr; break; case R_386_GOT32: /* we load the got offset */ *(int *)ptr += s1->got_offsets[sym_index]; break; } } /* if the relocation is allocated, we change its symbol table */ if (sr->sh_flags & SHF_ALLOC) sr->link = s1->dynsym;}/* relocate relocation table in 'sr' */static void relocate_rel(TCCState *s1, Section *sr){ Section *s; Elf32_Rel *rel, *rel_end; s = s1->sections[sr->sh_info]; rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); for(rel = (Elf32_Rel *)sr->data; rel < rel_end; 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){ Elf32_Rel *rel, *rel_end; int sym_index, esym_index, type, count; count = 0; rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++) { sym_index = ELF32_R_SYM(rel->r_info); type = ELF32_R_TYPE(rel->r_info); switch(type) { case R_386_32: count++; break; case R_386_PC32: esym_index = s1->symtab_to_dynsym[sym_index]; if (esym_index) count++; break; default: break; } } if (count) { /* allocate the section */ sr->sh_flags |= SHF_ALLOC; sr->sh_size = count * sizeof(Elf32_Rel); } return count;}static void put_got_offset(TCCState *s1, int index, unsigned long val){ int n; unsigned long *tab; if (index >= s1->nb_got_offsets) { /* find immediately bigger power of 2 and reallocate array */ n = 1; while (index >= n) n *= 2; tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long)); if (!tab) error("memory full"); s1->got_offsets = tab; memset(s1->got_offsets + s1->nb_got_offsets, 0, (n - s1->nb_got_offsets) * sizeof(unsigned long)); s1->nb_got_offsets = n; } s1->got_offsets[index] = val;}/* XXX: suppress that */static void put32(unsigned char *p, uint32_t val){ p[0] = val; p[1] = val >> 8; p[2] = val >> 16; p[3] = val >> 24;}static uint32_t get32(unsigned char *p){ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);}static void build_got(TCCState *s1){ unsigned char *ptr; /* if no got, then create it */ s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); s1->got->sh_entsize = 4; add_elf_sym(symtab_section, 0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); ptr = section_ptr_add(s1->got, 3 * sizeof(int)); /* keep space for _DYNAMIC pointer, if present */ put32(ptr, 0); /* two dummy got entries */ put32(ptr + 4, 0); put32(ptr + 8, 0);}/* put a got entry corresponding to a symbol in symtab_section. 'size' and 'info' can be modifed if more precise info comes from the DLL */static void put_got_entry(TCCState *s1, int reloc_type, unsigned long size, int info, int sym_index){ int index; const char *name; Elf32_Sym *sym; unsigned long offset; int *ptr; if (!s1->got) build_got(s1); /* if a got entry already exists for that symbol, no need to add one */ if (sym_index < s1->nb_got_offsets && s1->got_offsets[sym_index] != 0) return; put_got_offset(s1, sym_index, s1->got->data_offset); if (s1->dynsym) { sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; name = symtab_section->link->data + sym->st_name; offset = sym->st_value; if (reloc_type == R_386_JMP_SLOT) { Section *plt; uint8_t *p; int modrm; /* if we build a DLL, we add a %ebx offset */ if (s1->output_type == TCC_OUTPUT_DLL) modrm = 0xa3; else modrm = 0x25; /* add a PLT entry */ plt = s1->plt; if (plt->data_offset == 0) { /* first plt entry */ p = section_ptr_add(plt, 16); p[0] = 0xff; /* pushl got + 4 */ p[1] = modrm + 0x10; put32(p + 2, 4); p[6] = 0xff; /* jmp *(got + 8) */ p[7] = modrm; put32(p + 8, 8); } 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); p[11] = 0xe9; /* jmp plt_start */ put32(p + 12, -(plt->data_offset)); /* the symbol is modified so that it will be relocated to the PLT */ if (s1->output_type == TCC_OUTPUT_EXE) offset = plt->data_offset - 16; } index = put_elf_sym(s1->dynsym, offset, size, info, 0, sym->st_shndx, name); /* put a got entry */ put_elf_reloc(s1->dynsym, s1->got, s1->got->data_offset, reloc_type, index); } ptr = section_ptr_add(s1->got, sizeof(int)); *ptr = 0;}/* build GOT and PLT entries */static void build_got_entries(TCCState *s1){ Section *s, *symtab; Elf32_Rel *rel, *rel_end; Elf32_Sym *sym; int i, type, reloc_type, sym_index; for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; if (s->sh_type != SHT_REL) continue; /* no need to handle got relocations */ if (s->link != symtab_section) continue; symtab = s->link; rel_end = (Elf32_Rel *)(s->data + s->data_offset); for(rel = (Elf32_Rel *)s->data; rel < rel_end; rel++) { type = ELF32_R_TYPE(rel->r_info); switch(type) { case R_386_GOT32: case R_386_GOTOFF: case R_386_GOTPC: case R_386_PLT32: if (!s1->got) build_got(s1); if (type == R_386_GOT32 || type == R_386_PLT32) { sym_index = ELF32_R_SYM(rel->r_info); sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; /* look at the symbol got offset. If none, then add one */ if (type == R_386_GOT32) reloc_type = R_386_GLOB_DAT; else reloc_type = R_386_JMP_SLOT; put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, sym_index); } break; default: break; } } }}static Section *new_symtab(TCCState *s1, const char *symtab_name, int sh_type, int sh_flags, const char *strtab_name, const char *hash_name, int hash_sh_flags){ Section *symtab, *strtab, *hash; int *ptr, nb_buckets; symtab = new_section(s1, symtab_name, sh_type, sh_flags); symtab->sh_entsize = sizeof(Elf32_Sym); strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); put_elf_str(strtab, ""); symtab->link = strtab; put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); nb_buckets = 1; hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); hash->sh_entsize = sizeof(int); symtab->hash = hash; hash->link = symtab; ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); ptr[0] = nb_buckets; ptr[1] = 1; memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); return symtab;}/* put dynamic tag */static void put_dt(Section *dynamic, int dt, unsigned long val){ Elf32_Dyn *dyn; dyn = section_ptr_add(dynamic, sizeof(Elf32_Dyn)); dyn->d_tag = dt; dyn->d_un.d_val = val;}static void add_init_array_defines(TCCState *s1, const char *section_name){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -