diff options
| author | Thomas Preud'homme <robotux@celest.fr> | 2016-11-12 23:16:07 +0800 |
|---|---|---|
| committer | Thomas Preud'homme <robotux@celest.fr> | 2016-12-03 17:26:51 +0000 |
| commit | 1c811a4d1db56e4ed4fefa99ea39c679aa0c29f0 (patch) | |
| tree | 13775d557fedc7cd4c1922e39fa73ef58a7d0130 /tccelf.c | |
| parent | 523b55d82d455951659868d68eb54c4f5dbfb5a4 (diff) | |
| download | tinycc-1c811a4d1db56e4ed4fefa99ea39c679aa0c29f0.tar.gz tinycc-1c811a4d1db56e4ed4fefa99ea39c679aa0c29f0.tar.bz2 | |
Make build_got_entries more target independent
Factor most of common logic between targets in build_got_entries by
defining target specific info into structures in the backends.
Diffstat (limited to 'tccelf.c')
| -rw-r--r-- | tccelf.c | 263 |
1 files changed, 56 insertions, 207 deletions
@@ -1022,6 +1022,7 @@ ST_FUNC void build_got_entries(TCCState *s1) ElfW_Rel *rel; ElfW(Sym) *sym; int i, type, reloc_type, sym_index; + unsigned long ofs; for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; @@ -1034,222 +1035,70 @@ ST_FUNC void build_got_entries(TCCState *s1) type = ELFW(R_TYPE)(rel->r_info); sym_index = ELFW(R_SYM)(rel->r_info); sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - switch(type) { -#if defined(TCC_TARGET_I386) - case R_386_PC16: - case R_386_PC32: - case R_386_GOT32: - case R_386_GOT32X: - case R_386_GOTOFF: - case R_386_GOTPC: - case R_386_PLT32: - if (sym->st_shndx != SHN_UNDEF && type != R_386_GOT32 && - type != R_386_GOT32X && type != R_386_GOTOFF && - type != R_386_GOTPC && type != R_386_PLT32) - break; - - if (!s1->got) - build_got(s1); + if (relocs_info[type].gotplt_entry == NO_GOTPLT_ENTRY) + continue; - if (type != R_386_GOTOFF && type != R_386_GOTPC) { - /* look at the symbol got offset. If none, then add one */ - if (type == R_386_GOT32 || type == R_386_GOT32X) - 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; -#elif defined(TCC_TARGET_ARM) - case R_ARM_PC24: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_PLT32: - case R_ARM_THM_PC22: - case R_ARM_MOVT_ABS: - case R_ARM_MOVW_ABS_NC: - case R_ARM_THM_MOVT_ABS: - case R_ARM_THM_MOVW_ABS_NC: - case R_ARM_PREL31: - case R_ARM_REL32: - case R_ARM_GOTPC: - case R_ARM_GOTOFF: - case R_ARM_GOT32: - case R_ARM_V4BX: - if (sym->st_shndx != SHN_UNDEF && type != R_ARM_GOT32 && - type != R_ARM_GOTOFF && type != R_ARM_GOTPC && - type != R_ARM_PLT32) - break; + /* Proceed with PLT/GOT [entry] creation if any of the following + condition is met: + - it is an undefined reference (dynamic relocation needed) + - symbol is absolute (probably created by tcc_add_symbol) + - relocation requires a PLT/GOT (BUILD_GOTPLT_ENTRY or + ALWAYS_GOTPLT_ENTRY). */ + if (sym->st_shndx != SHN_UNDEF && + sym->st_shndx != SHN_ABS && + relocs_info[type].gotplt_entry == AUTO_GOTPLT_ENTRY) + continue; - if (!s1->got) - build_got(s1); - if (type != R_ARM_GOTOFF && type != R_ARM_GOTPC - && (sym->st_shndx == SHN_UNDEF - || s1->output_type == TCC_OUTPUT_MEMORY)) { - unsigned long ofs; - /* look at the symbol got offset. If none, then add one */ - if (type == R_ARM_GOT32 || type == R_ARM_MOVT_ABS || - type == R_ARM_MOVW_ABS_NC || - type == R_ARM_THM_MOVT_ABS || - type == R_ARM_THM_MOVW_ABS_NC || type == R_ARM_ABS32 || - type == R_ARM_REL32) - reloc_type = R_ARM_GLOB_DAT; - else - reloc_type = R_ARM_JUMP_SLOT; - ofs = put_got_entry(s1, reloc_type, sym->st_size, - sym->st_info, sym_index); -#ifdef DEBUG_RELOC - printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", - (char *) symtab_section->link->data + sym->st_name, - type, sym->st_shndx, ofs); -#endif - if (type == R_ARM_PC24 || type == R_ARM_CALL || - type == R_ARM_JUMP24 || type == R_ARM_PLT32) { - addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data - + rel->r_offset); - /* x must be signed! */ - int x = *ptr & 0xffffff; - x = (x << 8) >> 8; - x <<= 2; - x += ofs; - x >>= 2; -#ifdef DEBUG_RELOC - printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, - (*ptr & 0xff000000) | x, x); +#ifdef TCC_TARGET_X86_64 + if (type == R_X86_64_PLT32 && + ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) { + rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); + continue; + } #endif - *ptr = (*ptr & 0xff000000) | x; - } - } - break; - case R_ARM_THM_JUMP24: - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - /* We are relocating a jump from thumb code to arm code */ - if (sym->st_shndx != SHN_UNDEF && !(sym->st_value & 1)) { - int index; - uint8_t *p; - char *name, buf[1024]; - Section *text_section; - name = (char *) symtab_section->link->data + sym->st_name; - text_section = s1->sections[sym->st_shndx]; - /* Modify reloc to target a thumb stub to switch to ARM */ - snprintf(buf, sizeof(buf), "%s_from_thumb", name); - index = put_elf_sym(symtab_section, - text_section->data_offset + 1, - sym->st_size, sym->st_info, 0, - sym->st_shndx, buf); - rel->r_info = ELFW(R_INFO)(index, type); - /* Create a thumb stub fonction to switch to ARM mode */ - put_elf_reloc(symtab_section, text_section, - text_section->data_offset + 4, R_ARM_JUMP24, - sym_index); - p = section_ptr_add(text_section, 8); - write32le(p, 0x4778); /* bx pc */ - write32le(p+2, 0x46c0); /* nop */ - write32le(p+4, 0xeafffffe); /* b $sym */ - } -#elif defined(TCC_TARGET_ARM64) - //xx Other cases may be required here: - case R_AARCH64_ADR_GOT_PAGE: - case R_AARCH64_LD64_GOT_LO12_NC: - if (!s1->got) - build_got(s1); - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - reloc_type = R_AARCH64_GLOB_DAT; - put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, - sym_index); - break; + if (!s1->got) + build_got(s1); - case R_AARCH64_JUMP26: - case R_AARCH64_CALL26: - if (!s1->got) - build_got(s1); - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if (sym->st_shndx == SHN_UNDEF || - s1->output_type == TCC_OUTPUT_MEMORY) { - unsigned long ofs; - reloc_type = R_AARCH64_JUMP_SLOT; - ofs = put_got_entry(s1, reloc_type, sym->st_size, - sym->st_info, sym_index); - /* We store the place of the generated PLT slot - in our addend. */ - rel->r_addend += ofs; - } - break; -#elif defined(TCC_TARGET_C67) - case R_C60_GOT32: - case R_C60_GOTOFF: - case R_C60_GOTPC: - case R_C60_PLT32: - if (!s1->got) - build_got(s1); - if (type == R_C60_GOT32 || type == R_C60_PLT32) { - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - /* look at the symbol got offset. If none, then add one */ - if (type == R_C60_GOT32) - reloc_type = R_C60_GLOB_DAT; - else - reloc_type = R_C60_JMP_SLOT; - put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, - sym_index); - } - break; -#elif defined(TCC_TARGET_X86_64) - case R_X86_64_32: - case R_X86_64_32S: - case R_X86_64_64: - case R_X86_64_PC32: - case R_X86_64_GOT32: - case R_X86_64_GOTTPOFF: - case R_X86_64_GOTPCREL: - case R_X86_64_GOTPCRELX: - case R_X86_64_REX_GOTPCRELX: - case R_X86_64_PLT32: - sym_index = ELFW(R_SYM)(rel->r_info); - sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - if ((type == R_X86_64_32 || type == R_X86_64_32S || - type == R_X86_64_64 || type == R_X86_64_PC32) && - sym->st_shndx != SHN_UNDEF) - break; + if (relocs_info[type].gotplt_entry == BUILD_GOT_ONLY) + continue; - if (type == R_X86_64_PLT32 && - ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) { - rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); - break; - } + if (relocs_info[type].code_reloc) + reloc_type = R_JMP_SLOT; + else + reloc_type = R_GLOB_DAT; + ofs = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, + sym_index); - if (!s1->got) - build_got(s1); - if (type != R_X86_64_GOTTPOFF) { - unsigned long ofs; - /* look at the symbol got offset. If none, then add one */ - if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || - type == R_X86_64_GOTPCRELX || - type == R_X86_64_REX_GOTPCRELX || - type == R_X86_64_32 || type == R_X86_64_32S || - type == R_X86_64_64) - reloc_type = R_X86_64_GLOB_DAT; - else - reloc_type = R_X86_64_JUMP_SLOT; - ofs = put_got_entry(s1, reloc_type, sym->st_size, - sym->st_info, sym_index); - if (type == R_X86_64_PLT32) - /* We store the place of the generated PLT slot - in our addend. */ - rel->r_addend += ofs; - } - break; -#else -#error unsupported CPU +#ifdef DEBUG_RELOC + printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", + (char *) symtab_section->link->data + sym->st_name, type, + sym->st_shndx, ofs); #endif - default: - break; + +#if defined (TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64) + /* We store the place of the generated PLT slot in our addend. */ + if (relocs_info[type].pltoff_addend) + rel->r_addend += ofs; + +#elif defined (TCC_TARGET_ARM) + if (type == R_ARM_PC24 || type == R_ARM_CALL || + type == R_ARM_JUMP24 || type == R_ARM_PLT32) { + addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data + + rel->r_offset); + /* x must be signed! */ + int x = *ptr & 0xffffff; + x = (x << 8) >> 8; + x <<= 2; + x += ofs; + x >>= 2; +#ifdef DEBUG_RELOC + printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, + (*ptr & 0xff000000) | x, x); +#endif + *ptr = (*ptr & 0xff000000) | x; } +#endif } } } |
