📄 tccelf.c
字号:
{ return dlsym(RTLD_DEFAULT, sym);}/* 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; unsigned char *ptr; unsigned long val, addr;#if defined(TCC_TARGET_I386) int esym_index;#endif 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) {#if defined(TCC_TARGET_I386) 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;#elif defined(TCC_TARGET_ARM) case R_ARM_PC24: case R_ARM_PLT32: { int x; x = (*(int *)ptr)&0xffffff; (*(int *)ptr) &= 0xff000000; if (x & 0x800000) x -= 0x1000000; x *= 4; x += val - addr; if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) error("can't relocate value at %x",addr); x >>= 2; x &= 0xffffff; (*(int *)ptr) |= x; } break; case R_ARM_ABS32: *(int *)ptr += val; break; case R_ARM_GOTPC: *(int *)ptr += s1->got->sh_addr - addr; break; case R_ARM_GOT32: /* we load the got offset */ *(int *)ptr += s1->got_offsets[sym_index]; break; case R_ARM_COPY: break; default: fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", type,addr,(unsigned int )ptr,val); break;#elif defined(TCC_TARGET_C67) case R_C60_32: *(int *)ptr += val; break; case R_C60LO16: { uint32_t orig; /* put the low 16 bits of the absolute address */ // add to what is already there orig = ((*(int *)(ptr )) >> 7) & 0xffff; orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; //patch both at once - assumes always in pairs Low - High *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); } break; case R_C60HI16: break; default: fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", type,addr,(unsigned int )ptr,val); break;#else#error unsupported processor#endif } } /* 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;}#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM)static uint32_t get32(unsigned char *p){ return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);}#endifstatic 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;#ifdef TCC_TARGET_I386 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; }#elif defined(TCC_TARGET_ARM) if (reloc_type == R_ARM_JUMP_SLOT) { Section *plt; uint8_t *p; /* if we build a DLL, we add a %ebx offset */ if (s1->output_type == TCC_OUTPUT_DLL) error("DLLs unimplemented!"); /* add a PLT entry */ plt = s1->plt; if (plt->data_offset == 0) { /* first plt entry */ p = section_ptr_add(plt, 16); put32(p , 0xe52de004); put32(p + 4, 0xe59fe010); put32(p + 8, 0xe08fe00e); put32(p + 12, 0xe5bef008); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -