Unified · Split
| @@ -80,14 +80,14 @@ C67_CROSS = c67-tcc$(EXESUF) · 79 unmodified lines | ||
| 80 | 80 | |
| 81 | 81 | CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c |
| 82 | 82 | CORE_FILES += tcc.h config.h libtcc.h tcctok.h |
| 83 | −I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h | |
| 84 | −WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c | |
| 85 | −WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c | |
| 86 | −WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c | |
| 87 | −X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h | |
| 88 | −ARM_FILES = $(CORE_FILES) arm-gen.c | |
| 89 | −ARM64_FILES = $(CORE_FILES) arm64-gen.c | |
| 90 | −C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c | |
| 83 | +I386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h | |
| 84 | +WIN32_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h tccpe.c | |
| 85 | +WIN64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h tccpe.c | |
| 86 | +WINCE_FILES = $(CORE_FILES) arm-gen.c arm-link.c tccpe.c | |
| 87 | +X86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h | |
| 88 | +ARM_FILES = $(CORE_FILES) arm-gen.c arm-link.c | |
| 89 | +ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c | |
| 90 | +C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c | |
| 91 | 91 | |
| 92 | 92 | ifdef CONFIG_WIN32 |
| 93 | 93 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) $(LIBTCC) |
| @@ -0,0 +1,204 @@ | ||
| 1 | +#include "tcc.h" | |
| 2 | +#define HAVE_SECTION_RELOC | |
| 3 | + | |
| 4 | +void relocate_init(Section *sr) {} | |
| 5 | + | |
| 6 | +void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | |
| 7 | +{ | |
| 8 | + ElfW(Sym) *sym; | |
| 9 | + int sym_index; | |
| 10 | + | |
| 11 | + sym_index = ELFW(R_SYM)(rel->r_info); | |
| 12 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | |
| 13 | + | |
| 14 | + switch(type) { | |
| 15 | + case R_ARM_PC24: | |
| 16 | + case R_ARM_CALL: | |
| 17 | + case R_ARM_JUMP24: | |
| 18 | + case R_ARM_PLT32: | |
| 19 | + { | |
| 20 | + int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; | |
| 21 | + x = (*(int *) ptr) & 0xffffff; | |
| 22 | + if (sym->st_shndx == SHN_UNDEF || | |
| 23 | + s1->output_type == TCC_OUTPUT_MEMORY) | |
| 24 | + val = s1->plt->sh_addr; | |
| 25 | +#ifdef DEBUG_RELOC | |
| 26 | + printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); | |
| 27 | +#endif | |
| 28 | + (*(int *)ptr) &= 0xff000000; | |
| 29 | + if (x & 0x800000) | |
| 30 | + x -= 0x1000000; | |
| 31 | + x <<= 2; | |
| 32 | + blx_avail = (TCC_ARM_VERSION >= 5); | |
| 33 | + is_thumb = val & 1; | |
| 34 | + is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; | |
| 35 | + is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); | |
| 36 | + x += val - addr; | |
| 37 | +#ifdef DEBUG_RELOC | |
| 38 | + printf (" newx=0x%x name=%s\n", x, | |
| 39 | + (char *) symtab_section->link->data + sym->st_name); | |
| 40 | +#endif | |
| 41 | + h = x & 2; | |
| 42 | + th_ko = (x & 3) && (!blx_avail || !is_call); | |
| 43 | + if (th_ko || x >= 0x2000000 || x < -0x2000000) | |
| 44 | + tcc_error("can't relocate value at %x,%d",addr, type); | |
| 45 | + x >>= 2; | |
| 46 | + x &= 0xffffff; | |
| 47 | + /* Only reached if blx is avail and it is a call */ | |
| 48 | + if (is_thumb) { | |
| 49 | + x |= h << 24; | |
| 50 | + (*(int *)ptr) = 0xfa << 24; /* bl -> blx */ | |
| 51 | + } | |
| 52 | + (*(int *) ptr) |= x; | |
| 53 | + } | |
| 54 | + return; | |
| 55 | + /* Since these relocations only concern Thumb-2 and blx instruction was | |
| 56 | + introduced before Thumb-2, we can assume blx is available and not | |
| 57 | + guard its use */ | |
| 58 | + case R_ARM_THM_PC22: | |
| 59 | + case R_ARM_THM_JUMP24: | |
| 60 | + { | |
| 61 | + int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; | |
| 62 | + int to_thumb, is_call, to_plt, blx_bit = 1 << 12; | |
| 63 | + Section *plt; | |
| 64 | + | |
| 65 | + /* weak reference */ | |
| 66 | + if (sym->st_shndx == SHN_UNDEF && | |
| 67 | + ELFW(ST_BIND)(sym->st_info) == STB_WEAK) | |
| 68 | + return; | |
| 69 | + | |
| 70 | + /* Get initial offset */ | |
| 71 | + hi = (*(uint16_t *)ptr); | |
| 72 | + lo = (*(uint16_t *)(ptr+2)); | |
| 73 | + s = (hi >> 10) & 1; | |
| 74 | + j1 = (lo >> 13) & 1; | |
| 75 | + j2 = (lo >> 11) & 1; | |
| 76 | + i1 = (j1 ^ s) ^ 1; | |
| 77 | + i2 = (j2 ^ s) ^ 1; | |
| 78 | + imm10 = hi & 0x3ff; | |
| 79 | + imm11 = lo & 0x7ff; | |
| 80 | + x = (s << 24) | (i1 << 23) | (i2 << 22) | | |
| 81 | + (imm10 << 12) | (imm11 << 1); | |
| 82 | + if (x & 0x01000000) | |
| 83 | + x -= 0x02000000; | |
| 84 | + | |
| 85 | + /* Relocation infos */ | |
| 86 | + to_thumb = val & 1; | |
| 87 | + plt = s1->plt; | |
| 88 | + to_plt = (val >= plt->sh_addr) && | |
| 89 | + (val < plt->sh_addr + plt->data_offset); | |
| 90 | + is_call = (type == R_ARM_THM_PC22); | |
| 91 | + | |
| 92 | + /* Compute final offset */ | |
| 93 | + if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ | |
| 94 | + x -= 4; | |
| 95 | + x += val - addr; | |
| 96 | + if (!to_thumb && is_call) { | |
| 97 | + blx_bit = 0; /* bl -> blx */ | |
| 98 | + x = (x + 3) & -4; /* Compute offset from aligned PC */ | |
| 99 | + } | |
| 100 | + | |
| 101 | + /* Check that relocation is possible | |
| 102 | + * offset must not be out of range | |
| 103 | + * if target is to be entered in arm mode: | |
| 104 | + - bit 1 must not set | |
| 105 | + - instruction must be a call (bl) or a jump to PLT */ | |
| 106 | + if (!to_thumb || x >= 0x1000000 || x < -0x1000000) | |
| 107 | + if (to_thumb || (val & 2) || (!is_call && !to_plt)) | |
| 108 | + tcc_error("can't relocate value at %x,%d",addr, type); | |
| 109 | + | |
| 110 | + /* Compute and store final offset */ | |
| 111 | + s = (x >> 24) & 1; | |
| 112 | + i1 = (x >> 23) & 1; | |
| 113 | + i2 = (x >> 22) & 1; | |
| 114 | + j1 = s ^ (i1 ^ 1); | |
| 115 | + j2 = s ^ (i2 ^ 1); | |
| 116 | + imm10 = (x >> 12) & 0x3ff; | |
| 117 | + imm11 = (x >> 1) & 0x7ff; | |
| 118 | + (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | | |
| 119 | + (s << 10) | imm10); | |
| 120 | + (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | | |
| 121 | + (j1 << 13) | blx_bit | (j2 << 11) | | |
| 122 | + imm11); | |
| 123 | + } | |
| 124 | + return; | |
| 125 | + case R_ARM_MOVT_ABS: | |
| 126 | + case R_ARM_MOVW_ABS_NC: | |
| 127 | + { | |
| 128 | + int x, imm4, imm12; | |
| 129 | + if (type == R_ARM_MOVT_ABS) | |
| 130 | + val >>= 16; | |
| 131 | + imm12 = val & 0xfff; | |
| 132 | + imm4 = (val >> 12) & 0xf; | |
| 133 | + x = (imm4 << 16) | imm12; | |
| 134 | + if (type == R_ARM_THM_MOVT_ABS) | |
| 135 | + *(int *)ptr |= x; | |
| 136 | + else | |
| 137 | + *(int *)ptr += x; | |
| 138 | + } | |
| 139 | + return; | |
| 140 | + case R_ARM_THM_MOVT_ABS: | |
| 141 | + case R_ARM_THM_MOVW_ABS_NC: | |
| 142 | + { | |
| 143 | + int x, i, imm4, imm3, imm8; | |
| 144 | + if (type == R_ARM_THM_MOVT_ABS) | |
| 145 | + val >>= 16; | |
| 146 | + imm8 = val & 0xff; | |
| 147 | + imm3 = (val >> 8) & 0x7; | |
| 148 | + i = (val >> 11) & 1; | |
| 149 | + imm4 = (val >> 12) & 0xf; | |
| 150 | + x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; | |
| 151 | + if (type == R_ARM_THM_MOVT_ABS) | |
| 152 | + *(int *)ptr |= x; | |
| 153 | + else | |
| 154 | + *(int *)ptr += x; | |
| 155 | + } | |
| 156 | + return; | |
| 157 | + case R_ARM_PREL31: | |
| 158 | + { | |
| 159 | + int x; | |
| 160 | + x = (*(int *)ptr) & 0x7fffffff; | |
| 161 | + (*(int *)ptr) &= 0x80000000; | |
| 162 | + x = (x * 2) / 2; | |
| 163 | + x += val - addr; | |
| 164 | + if((x^(x>>1))&0x40000000) | |
| 165 | + tcc_error("can't relocate value at %x,%d",addr, type); | |
| 166 | + (*(int *)ptr) |= x & 0x7fffffff; | |
| 167 | + } | |
| 168 | + case R_ARM_ABS32: | |
| 169 | + *(int *)ptr += val; | |
| 170 | + return; | |
| 171 | + case R_ARM_REL32: | |
| 172 | + *(int *)ptr += val - addr; | |
| 173 | + return; | |
| 174 | + case R_ARM_GOTPC: | |
| 175 | + *(int *)ptr += s1->got->sh_addr - addr; | |
| 176 | + return; | |
| 177 | + case R_ARM_GOTOFF: | |
| 178 | + *(int *)ptr += val - s1->got->sh_addr; | |
| 179 | + return; | |
| 180 | + case R_ARM_GOT32: | |
| 181 | + /* we load the got offset */ | |
| 182 | + *(int *)ptr += s1->sym_attrs[sym_index].got_offset; | |
| 183 | + return; | |
| 184 | + case R_ARM_COPY: | |
| 185 | + return; | |
| 186 | + case R_ARM_V4BX: | |
| 187 | + /* trade Thumb support for ARMv4 support */ | |
| 188 | + if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) | |
| 189 | + *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ | |
| 190 | + return; | |
| 191 | + case R_ARM_GLOB_DAT: | |
| 192 | + case R_ARM_JUMP_SLOT: | |
| 193 | + *(addr_t *)ptr = val; | |
| 194 | + return; | |
| 195 | + case R_ARM_NONE: | |
| 196 | + /* Nothing to do. Normally used to indicate a dependency | |
| 197 | + on a certain symbol (like for exception handling under EABI). */ | |
| 198 | + return; | |
| 199 | + default: | |
| 200 | + fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 201 | + type, (unsigned)addr, ptr, (unsigned)val); | |
| 202 | + return; | |
| 203 | + } | |
| 204 | +} | |
| @@ -0,0 +1,104 @@ | ||
| 1 | +#include "tcc.h" | |
| 2 | +#define HAVE_SECTION_RELOC | |
| 3 | + | |
| 4 | +void relocate_init(Section *sr) {} | |
| 5 | + | |
| 6 | +void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | |
| 7 | +{ | |
| 8 | + ElfW(Sym) *sym; | |
| 9 | + int sym_index; | |
| 10 | + | |
| 11 | + sym_index = ELFW(R_SYM)(rel->r_info); | |
| 12 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | |
| 13 | + | |
| 14 | + switch(type) { | |
| 15 | + case R_AARCH64_ABS64: | |
| 16 | + write64le(ptr, val); | |
| 17 | + return; | |
| 18 | + case R_AARCH64_ABS32: | |
| 19 | + write32le(ptr, val); | |
| 20 | + return; | |
| 21 | + case R_AARCH64_MOVW_UABS_G0_NC: | |
| 22 | + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 23 | + (val & 0xffff) << 5)); | |
| 24 | + return; | |
| 25 | + case R_AARCH64_MOVW_UABS_G1_NC: | |
| 26 | + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 27 | + (val >> 16 & 0xffff) << 5)); | |
| 28 | + return; | |
| 29 | + case R_AARCH64_MOVW_UABS_G2_NC: | |
| 30 | + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 31 | + (val >> 32 & 0xffff) << 5)); | |
| 32 | + return; | |
| 33 | + case R_AARCH64_MOVW_UABS_G3: | |
| 34 | + write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 35 | + (val >> 48 & 0xffff) << 5)); | |
| 36 | + return; | |
| 37 | + case R_AARCH64_ADR_PREL_PG_HI21: { | |
| 38 | + uint64_t off = (val >> 12) - (addr >> 12); | |
| 39 | + if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 40 | + tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); | |
| 41 | + write32le(ptr, ((read32le(ptr) & 0x9f00001f) | | |
| 42 | + (off & 0x1ffffc) << 3 | (off & 3) << 29)); | |
| 43 | + return; | |
| 44 | + } | |
| 45 | + case R_AARCH64_ADD_ABS_LO12_NC: | |
| 46 | + write32le(ptr, ((read32le(ptr) & 0xffc003ff) | | |
| 47 | + (val & 0xfff) << 10)); | |
| 48 | + return; | |
| 49 | + case R_AARCH64_JUMP26: | |
| 50 | + case R_AARCH64_CALL26: | |
| 51 | + /* This check must match the one in build_got_entries, testing | |
| 52 | + if we really need a PLT slot. */ | |
| 53 | + if (sym->st_shndx == SHN_UNDEF || | |
| 54 | + s1->output_type == TCC_OUTPUT_MEMORY) | |
| 55 | + /* We've put the PLT slot offset into r_addend when generating | |
| 56 | + it, and that's what we must use as relocation value (adjusted | |
| 57 | + by section offset of course). */ | |
| 58 | + val = s1->plt->sh_addr + rel->r_addend; | |
| 59 | +#ifdef DEBUG_RELOC | |
| 60 | + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, | |
| 61 | + (char *) symtab_section->link->data + sym->st_name); | |
| 62 | +#endif | |
| 63 | + if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) | |
| 64 | + { | |
| 65 | + tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); | |
| 66 | + } | |
| 67 | + write32le(ptr, (0x14000000 | | |
| 68 | + (uint32_t)(type == R_AARCH64_CALL26) << 31 | | |
| 69 | + ((val - addr) >> 2 & 0x3ffffff))); | |
| 70 | + return; | |
| 71 | + case R_AARCH64_ADR_GOT_PAGE: { | |
| 72 | + uint64_t off = | |
| 73 | + (((s1->got->sh_addr + | |
| 74 | + s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); | |
| 75 | + if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 76 | + tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); | |
| 77 | + write32le(ptr, ((read32le(ptr) & 0x9f00001f) | | |
| 78 | + (off & 0x1ffffc) << 3 | (off & 3) << 29)); | |
| 79 | + return; | |
| 80 | + } | |
| 81 | + case R_AARCH64_LD64_GOT_LO12_NC: | |
| 82 | + write32le(ptr, | |
| 83 | + ((read32le(ptr) & 0xfff803ff) | | |
| 84 | + ((s1->got->sh_addr + | |
| 85 | + s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); | |
| 86 | + return; | |
| 87 | + case R_AARCH64_COPY: | |
| 88 | + return; | |
| 89 | + case R_AARCH64_GLOB_DAT: | |
| 90 | + case R_AARCH64_JUMP_SLOT: | |
| 91 | + /* They don't need addend */ | |
| 92 | +#ifdef DEBUG_RELOC | |
| 93 | + printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, | |
| 94 | + val - rel->r_addend, | |
| 95 | + (char *) symtab_section->link->data + sym->st_name); | |
| 96 | +#endif | |
| 97 | + write64le(ptr, val - rel->r_addend); | |
| 98 | + return; | |
| 99 | + default: | |
| 100 | + fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 101 | + type, (unsigned)addr, ptr, (unsigned)val); | |
| 102 | + return; | |
| 103 | + } | |
| 104 | +} | |
| @@ -0,0 +1,35 @@ | ||
| 1 | +#include "tcc.h" | |
| 2 | +#define HAVE_SECTION_RELOC | |
| 3 | + | |
| 4 | +void relocate_init(Section *sr) {} | |
| 5 | + | |
| 6 | +void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | |
| 7 | +{ | |
| 8 | + switch(type) { | |
| 9 | + case R_C60_32: | |
| 10 | + *(int *)ptr += val; | |
| 11 | + break; | |
| 12 | + case R_C60LO16: | |
| 13 | + { | |
| 14 | + uint32_t orig; | |
| 15 | + | |
| 16 | + /* put the low 16 bits of the absolute address add to what is | |
| 17 | + already there */ | |
| 18 | + orig = ((*(int *)(ptr )) >> 7) & 0xffff; | |
| 19 | + orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; | |
| 20 | + | |
| 21 | + /* patch both at once - assumes always in pairs Low - High */ | |
| 22 | + *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | | |
| 23 | + (((val+orig) & 0xffff) << 7); | |
| 24 | + *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | | |
| 25 | + ((((val+orig)>>16) & 0xffff) << 7); | |
| 26 | + } | |
| 27 | + break; | |
| 28 | + case R_C60HI16: | |
| 29 | + break; | |
| 30 | + default: | |
| 31 | + fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 32 | + type, (unsigned) addr, ptr, (unsigned) val); | |
| 33 | + break; | |
| 34 | + } | |
| 35 | +} | |
| @@ -0,0 +1,90 @@ | ||
| 1 | +#include "tcc.h" | |
| 2 | +#define HAVE_SECTION_RELOC | |
| 3 | + | |
| 4 | +static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ | |
| 5 | + | |
| 6 | +void relocate_init(Section *sr) | |
| 7 | +{ | |
| 8 | + qrel = (ElfW_Rel *) sr->data; | |
| 9 | +} | |
| 10 | + | |
| 11 | +void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | |
| 12 | +{ | |
| 13 | + int sym_index, esym_index; | |
| 14 | + | |
| 15 | + sym_index = ELFW(R_SYM)(rel->r_info); | |
| 16 | + | |
| 17 | + switch (type) { | |
| 18 | + case R_386_32: | |
| 19 | + if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 20 | + esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 21 | + qrel->r_offset = rel->r_offset; | |
| 22 | + if (esym_index) { | |
| 23 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); | |
| 24 | + qrel++; | |
| 25 | + return; | |
| 26 | + } else { | |
| 27 | + qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); | |
| 28 | + qrel++; | |
| 29 | + } | |
| 30 | + } | |
| 31 | + add32le(ptr, val); | |
| 32 | + return; | |
| 33 | + case R_386_PC32: | |
| 34 | + if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 35 | + /* DLL relocation */ | |
| 36 | + esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 37 | + if (esym_index) { | |
| 38 | + qrel->r_offset = rel->r_offset; | |
| 39 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); | |
| 40 | + qrel++; | |
| 41 | + return; | |
| 42 | + } | |
| 43 | + } | |
| 44 | + add32le(ptr, val - addr); | |
| 45 | + return; | |
| 46 | + case R_386_PLT32: | |
| 47 | + add32le(ptr, val - addr); | |
| 48 | + return; | |
| 49 | + case R_386_GLOB_DAT: | |
| 50 | + case R_386_JMP_SLOT: | |
| 51 | + write32le(ptr, val); | |
| 52 | + return; | |
| 53 | + case R_386_GOTPC: | |
| 54 | + add32le(ptr, s1->got->sh_addr - addr); | |
| 55 | + return; | |
| 56 | + case R_386_GOTOFF: | |
| 57 | + add32le(ptr, val - s1->got->sh_addr); | |
| 58 | + return; | |
| 59 | + case R_386_GOT32: | |
| 60 | + case R_386_GOT32X: | |
| 61 | + /* we load the got offset */ | |
| 62 | + add32le(ptr, s1->sym_attrs[sym_index].got_offset); | |
| 63 | + return; | |
| 64 | + case R_386_16: | |
| 65 | + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { | |
| 66 | + output_file: | |
| 67 | + tcc_error("can only produce 16-bit binary files"); | |
| 68 | + } | |
| 69 | + write16le(ptr, read16le(ptr) + val); | |
| 70 | + return; | |
| 71 | + case R_386_PC16: | |
| 72 | + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) | |
| 73 | + goto output_file; | |
| 74 | + write16le(ptr, read16le(ptr) + val - addr); | |
| 75 | + return; | |
| 76 | + case R_386_RELATIVE: | |
| 77 | + /* do nothing */ | |
| 78 | + return; | |
| 79 | + case R_386_COPY: | |
| 80 | + /* This reloction must copy initialized data from the library | |
| 81 | + to the program .bss segment. Currently made like for ARM | |
| 82 | + (to remove noise of defaukt case). Is this true? | |
| 83 | + */ | |
| 84 | + return; | |
| 85 | + default: | |
| 86 | + fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", | |
| 87 | + type, (unsigned)addr, ptr, (unsigned)val); | |
| 88 | + return; | |
| 89 | + } | |
| 90 | +} | |
| @@ -41,18 +41,23 @@ ST_DATA struct TCCState *tcc_state; · 40 unmodified lines | ||
| 41 | 41 | #include "tccrun.c" |
| 42 | 42 | #ifdef TCC_TARGET_I386 |
| 43 | 43 | #include "i386-gen.c" |
| 44 | +#include "i386-link.c" | |
| 44 | 45 | #endif |
| 45 | 46 | #ifdef TCC_TARGET_ARM |
| 46 | 47 | #include "arm-gen.c" |
| 48 | +#include "arm-link.c" | |
| 47 | 49 | #endif |
| 48 | 50 | #ifdef TCC_TARGET_ARM64 |
| 49 | 51 | #include "arm64-gen.c" |
| 52 | +#include "arm64-link.c" | |
| 50 | 53 | #endif |
| 51 | 54 | #ifdef TCC_TARGET_C67 |
| 52 | 55 | #include "c67-gen.c" |
| 56 | +#include "c67-link.c" | |
| 53 | 57 | #endif |
| 54 | 58 | #ifdef TCC_TARGET_X86_64 |
| 55 | 59 | #include "x86_64-gen.c" |
| 60 | +#include "x86_64-link.c" | |
| 56 | 61 | #endif |
| 57 | 62 | #ifdef CONFIG_TCC_ASM |
| 58 | 63 | #include "tccasm.c" |
| @@ -1485,6 +1485,11 @@ ST_FUNC void gen_clear_cache(void); · 1484 unmodified lines | ||
| 1485 | 1485 | #ifdef TCC_TARGET_C67 |
| 1486 | 1486 | #endif |
| 1487 | 1487 | |
| 1488 | +/* ------------ xxx-link.c ------------ */ | |
| 1489 | + | |
| 1490 | +ST_FUNC void relocate_init(Section *sr); | |
| 1491 | +ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val); | |
| 1492 | + | |
| 1488 | 1493 | /* ------------ tcccoff.c ------------ */ |
| 1489 | 1494 | |
| 1490 | 1495 | #ifdef TCC_TARGET_COFF |
| @@ -694,11 +694,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 693 unmodified lines | ||
| 694 | 694 | int type, sym_index; |
| 695 | 695 | unsigned char *ptr; |
| 696 | 696 | addr_t val, addr; |
| 697 | −#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 | |
| 698 | − ElfW_Rel *qrel = (ElfW_Rel *) sr->data; /* ptr to next reloc entry reused */ | |
| 699 | − int esym_index; | |
| 700 | −#endif | |
| 701 | 697 | |
| 698 | + relocate_init(sr); | |
| 702 | 699 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
| 703 | 700 | ptr = s->data + rel->r_offset; |
| 704 | 701 | |
| @@ -711,484 +708,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 6 unmodified lines | ||
| 711 | 708 | type = ELFW(R_TYPE)(rel->r_info); |
| 712 | 709 | addr = s->sh_addr + rel->r_offset; |
| 713 | 710 | |
| 714 | − /* CPU specific */ | |
| 715 | − switch(type) { | |
| 716 | −#if defined(TCC_TARGET_I386) | |
| 717 | − case R_386_32: | |
| 718 | − if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 719 | − esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 720 | − qrel->r_offset = rel->r_offset; | |
| 721 | − if (esym_index) { | |
| 722 | − qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); | |
| 723 | − qrel++; | |
| 724 | − break; | |
| 725 | − } else { | |
| 726 | − qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); | |
| 727 | − qrel++; | |
| 728 | − } | |
| 729 | − } | |
| 730 | − add32le(ptr, val); | |
| 731 | − break; | |
| 732 | − case R_386_PC32: | |
| 733 | − if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 734 | − /* DLL relocation */ | |
| 735 | − esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 736 | − if (esym_index) { | |
| 737 | − qrel->r_offset = rel->r_offset; | |
| 738 | − qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); | |
| 739 | − qrel++; | |
| 740 | − break; | |
| 741 | − } | |
| 742 | − } | |
| 743 | − add32le(ptr, val - addr); | |
| 744 | − break; | |
| 745 | − case R_386_PLT32: | |
| 746 | − add32le(ptr, val - addr); | |
| 747 | − break; | |
| 748 | − case R_386_GLOB_DAT: | |
| 749 | − case R_386_JMP_SLOT: | |
| 750 | − write32le(ptr, val); | |
| 751 | − break; | |
| 752 | − case R_386_GOTPC: | |
| 753 | − add32le(ptr, s1->got->sh_addr - addr); | |
| 754 | − break; | |
| 755 | − case R_386_GOTOFF: | |
| 756 | − add32le(ptr, val - s1->got->sh_addr); | |
| 757 | − break; | |
| 758 | − case R_386_GOT32: | |
| 759 | − case R_386_GOT32X: | |
| 760 | − /* we load the got offset */ | |
| 761 | − add32le(ptr, s1->sym_attrs[sym_index].got_offset); | |
| 762 | − break; | |
| 763 | − case R_386_16: | |
| 764 | − if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { | |
| 765 | − output_file: | |
| 766 | − tcc_error("can only produce 16-bit binary files"); | |
| 767 | − } | |
| 768 | − write16le(ptr, read16le(ptr) + val); | |
| 769 | − break; | |
| 770 | − case R_386_PC16: | |
| 771 | − if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) | |
| 772 | − goto output_file; | |
| 773 | − write16le(ptr, read16le(ptr) + val - addr); | |
| 774 | − break; | |
| 775 | − | |
| 776 | −#ifdef TCC_TARGET_PE | |
| 777 | − case R_386_RELATIVE: /* handled in pe_relocate_rva() */ | |
| 778 | − break; | |
| 779 | −#endif | |
| 780 | − case R_386_COPY: | |
| 781 | − /* This reloction must copy initialized data from the library | |
| 782 | − to the program .bss segment. Currently made like for ARM | |
| 783 | − (to remove noise of defaukt case). Is this true? | |
| 784 | − */ | |
| 785 | − break; | |
| 786 | − | |
| 787 | − default: | |
| 788 | − fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", | |
| 789 | − type, (unsigned)addr, ptr, (unsigned)val); | |
| 790 | − break; | |
| 791 | −#elif defined(TCC_TARGET_ARM) | |
| 792 | − case R_ARM_PC24: | |
| 793 | − case R_ARM_CALL: | |
| 794 | − case R_ARM_JUMP24: | |
| 795 | − case R_ARM_PLT32: | |
| 796 | − { | |
| 797 | − int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; | |
| 798 | − x = (*(int *) ptr) & 0xffffff; | |
| 799 | − if (sym->st_shndx == SHN_UNDEF | |
| 800 | − || s1->output_type == TCC_OUTPUT_MEMORY) | |
| 801 | − val = s1->plt->sh_addr; | |
| 802 | −#ifdef DEBUG_RELOC | |
| 803 | − printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); | |
| 804 | −#endif | |
| 805 | − (*(int *)ptr) &= 0xff000000; | |
| 806 | − if (x & 0x800000) | |
| 807 | − x -= 0x1000000; | |
| 808 | − x <<= 2; | |
| 809 | − blx_avail = (TCC_ARM_VERSION >= 5); | |
| 810 | − is_thumb = val & 1; | |
| 811 | − is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; | |
| 812 | − is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); | |
| 813 | − x += val - addr; | |
| 814 | −#ifdef DEBUG_RELOC | |
| 815 | − printf (" newx=0x%x name=%s\n", x, | |
| 816 | − (char *) symtab_section->link->data + sym->st_name); | |
| 817 | −#endif | |
| 818 | − h = x & 2; | |
| 819 | − th_ko = (x & 3) && (!blx_avail || !is_call); | |
| 820 | − if (th_ko || x >= 0x2000000 || x < -0x2000000) | |
| 821 | − tcc_error("can't relocate value at %x,%d",addr, type); | |
| 822 | − x >>= 2; | |
| 823 | − x &= 0xffffff; | |
| 824 | − /* Only reached if blx is avail and it is a call */ | |
| 825 | − if (is_thumb) { | |
| 826 | − x |= h << 24; | |
| 827 | − (*(int *)ptr) = 0xfa << 24; /* bl -> blx */ | |
| 828 | − } | |
| 829 | − (*(int *) ptr) |= x; | |
| 830 | − } | |
| 831 | − break; | |
| 832 | − /* Since these relocations only concern Thumb-2 and blx instruction was | |
| 833 | − introduced before Thumb-2, we can assume blx is available and not | |
| 834 | − guard its use */ | |
| 835 | − case R_ARM_THM_PC22: | |
| 836 | − case R_ARM_THM_JUMP24: | |
| 837 | − { | |
| 838 | − int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; | |
| 839 | − int to_thumb, is_call, to_plt, blx_bit = 1 << 12; | |
| 840 | − Section *plt; | |
| 841 | − | |
| 842 | − /* weak reference */ | |
| 843 | − if (sym->st_shndx == SHN_UNDEF && | |
| 844 | − ELFW(ST_BIND)(sym->st_info) == STB_WEAK) | |
| 845 | − break; | |
| 846 | − | |
| 847 | − /* Get initial offset */ | |
| 848 | − hi = (*(uint16_t *)ptr); | |
| 849 | − lo = (*(uint16_t *)(ptr+2)); | |
| 850 | − s = (hi >> 10) & 1; | |
| 851 | − j1 = (lo >> 13) & 1; | |
| 852 | − j2 = (lo >> 11) & 1; | |
| 853 | − i1 = (j1 ^ s) ^ 1; | |
| 854 | − i2 = (j2 ^ s) ^ 1; | |
| 855 | − imm10 = hi & 0x3ff; | |
| 856 | − imm11 = lo & 0x7ff; | |
| 857 | − x = (s << 24) | (i1 << 23) | (i2 << 22) | | |
| 858 | − (imm10 << 12) | (imm11 << 1); | |
| 859 | − if (x & 0x01000000) | |
| 860 | − x -= 0x02000000; | |
| 861 | − | |
| 862 | − /* Relocation infos */ | |
| 863 | − to_thumb = val & 1; | |
| 864 | − plt = s1->plt; | |
| 865 | − to_plt = (val >= plt->sh_addr) && | |
| 866 | − (val < plt->sh_addr + plt->data_offset); | |
| 867 | − is_call = (type == R_ARM_THM_PC22); | |
| 868 | − | |
| 869 | − /* Compute final offset */ | |
| 870 | − if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ | |
| 871 | − x -= 4; | |
| 872 | − x += val - addr; | |
| 873 | − if (!to_thumb && is_call) { | |
| 874 | − blx_bit = 0; /* bl -> blx */ | |
| 875 | − x = (x + 3) & -4; /* Compute offset from aligned PC */ | |
| 876 | − } | |
| 877 | − | |
| 878 | − /* Check that relocation is possible | |
| 879 | − * offset must not be out of range | |
| 880 | − * if target is to be entered in arm mode: | |
| 881 | − - bit 1 must not set | |
| 882 | − - instruction must be a call (bl) or a jump to PLT */ | |
| 883 | − if (!to_thumb || x >= 0x1000000 || x < -0x1000000) | |
| 884 | − if (to_thumb || (val & 2) || (!is_call && !to_plt)) | |
| 885 | − tcc_error("can't relocate value at %x,%d",addr, type); | |
| 886 | − | |
| 887 | − /* Compute and store final offset */ | |
| 888 | − s = (x >> 24) & 1; | |
| 889 | − i1 = (x >> 23) & 1; | |
| 890 | − i2 = (x >> 22) & 1; | |
| 891 | − j1 = s ^ (i1 ^ 1); | |
| 892 | − j2 = s ^ (i2 ^ 1); | |
| 893 | − imm10 = (x >> 12) & 0x3ff; | |
| 894 | − imm11 = (x >> 1) & 0x7ff; | |
| 895 | − (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | | |
| 896 | − (s << 10) | imm10); | |
| 897 | − (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | | |
| 898 | − (j1 << 13) | blx_bit | (j2 << 11) | | |
| 899 | − imm11); | |
| 900 | − } | |
| 901 | − break; | |
| 902 | − case R_ARM_MOVT_ABS: | |
| 903 | − case R_ARM_MOVW_ABS_NC: | |
| 904 | − { | |
| 905 | − int x, imm4, imm12; | |
| 906 | − if (type == R_ARM_MOVT_ABS) | |
| 907 | − val >>= 16; | |
| 908 | − imm12 = val & 0xfff; | |
| 909 | − imm4 = (val >> 12) & 0xf; | |
| 910 | − x = (imm4 << 16) | imm12; | |
| 911 | − if (type == R_ARM_THM_MOVT_ABS) | |
| 912 | − *(int *)ptr |= x; | |
| 913 | − else | |
| 914 | − *(int *)ptr += x; | |
| 915 | − } | |
| 916 | − break; | |
| 917 | − case R_ARM_THM_MOVT_ABS: | |
| 918 | − case R_ARM_THM_MOVW_ABS_NC: | |
| 919 | − { | |
| 920 | − int x, i, imm4, imm3, imm8; | |
| 921 | − if (type == R_ARM_THM_MOVT_ABS) | |
| 922 | − val >>= 16; | |
| 923 | − imm8 = val & 0xff; | |
| 924 | − imm3 = (val >> 8) & 0x7; | |
| 925 | − i = (val >> 11) & 1; | |
| 926 | − imm4 = (val >> 12) & 0xf; | |
| 927 | − x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; | |
| 928 | − if (type == R_ARM_THM_MOVT_ABS) | |
| 929 | − *(int *)ptr |= x; | |
| 930 | − else | |
| 931 | − *(int *)ptr += x; | |
| 932 | − } | |
| 933 | − break; | |
| 934 | − case R_ARM_PREL31: | |
| 935 | − { | |
| 936 | − int x; | |
| 937 | − x = (*(int *)ptr) & 0x7fffffff; | |
| 938 | − (*(int *)ptr) &= 0x80000000; | |
| 939 | − x = (x * 2) / 2; | |
| 940 | − x += val - addr; | |
| 941 | − if((x^(x>>1))&0x40000000) | |
| 942 | − tcc_error("can't relocate value at %x,%d",addr, type); | |
| 943 | − (*(int *)ptr) |= x & 0x7fffffff; | |
| 944 | − } | |
| 945 | − case R_ARM_ABS32: | |
| 946 | − *(int *)ptr += val; | |
| 947 | − break; | |
| 948 | − case R_ARM_REL32: | |
| 949 | − *(int *)ptr += val - addr; | |
| 950 | − break; | |
| 951 | − case R_ARM_GOTPC: | |
| 952 | − *(int *)ptr += s1->got->sh_addr - addr; | |
| 953 | − break; | |
| 954 | − case R_ARM_GOTOFF: | |
| 955 | − *(int *)ptr += val - s1->got->sh_addr; | |
| 956 | − break; | |
| 957 | − case R_ARM_GOT32: | |
| 958 | − /* we load the got offset */ | |
| 959 | − *(int *)ptr += s1->sym_attrs[sym_index].got_offset; | |
| 960 | − break; | |
| 961 | − case R_ARM_COPY: | |
| 962 | − break; | |
| 963 | − case R_ARM_V4BX: | |
| 964 | − /* trade Thumb support for ARMv4 support */ | |
| 965 | − if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) | |
| 966 | − *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ | |
| 967 | − break; | |
| 968 | − case R_ARM_GLOB_DAT: | |
| 969 | − case R_ARM_JUMP_SLOT: | |
| 970 | − *(addr_t *)ptr = val; | |
| 971 | − break; | |
| 972 | − case R_ARM_NONE: | |
| 973 | − /* Nothing to do. Normally used to indicate a dependency | |
| 974 | − on a certain symbol (like for exception handling under EABI). */ | |
| 975 | − break; | |
| 976 | −#ifdef TCC_TARGET_PE | |
| 977 | − case R_ARM_RELATIVE: /* handled in pe_relocate_rva() */ | |
| 978 | − break; | |
| 979 | −#endif | |
| 980 | − default: | |
| 981 | − fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 982 | − type, (unsigned)addr, ptr, (unsigned)val); | |
| 983 | − break; | |
| 984 | −#elif defined(TCC_TARGET_ARM64) | |
| 985 | − case R_AARCH64_ABS64: | |
| 986 | − write64le(ptr, val); | |
| 987 | − break; | |
| 988 | − case R_AARCH64_ABS32: | |
| 989 | − write32le(ptr, val); | |
| 990 | − break; | |
| 991 | − case R_AARCH64_PREL32: | |
| 992 | − write32le(ptr, val - addr); | |
| 993 | − break; | |
| 994 | − case R_AARCH64_MOVW_UABS_G0_NC: | |
| 995 | − write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 996 | − (val & 0xffff) << 5)); | |
| 997 | − break; | |
| 998 | − case R_AARCH64_MOVW_UABS_G1_NC: | |
| 999 | − write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 1000 | − (val >> 16 & 0xffff) << 5)); | |
| 1001 | − break; | |
| 1002 | − case R_AARCH64_MOVW_UABS_G2_NC: | |
| 1003 | − write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 1004 | − (val >> 32 & 0xffff) << 5)); | |
| 1005 | − break; | |
| 1006 | − case R_AARCH64_MOVW_UABS_G3: | |
| 1007 | − write32le(ptr, ((read32le(ptr) & 0xffe0001f) | | |
| 1008 | − (val >> 48 & 0xffff) << 5)); | |
| 1009 | − break; | |
| 1010 | − case R_AARCH64_ADR_PREL_PG_HI21: { | |
| 1011 | − uint64_t off = (val >> 12) - (addr >> 12); | |
| 1012 | − if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 1013 | − tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); | |
| 1014 | − write32le(ptr, ((read32le(ptr) & 0x9f00001f) | | |
| 1015 | − (off & 0x1ffffc) << 3 | (off & 3) << 29)); | |
| 1016 | − break; | |
| 1017 | − } | |
| 1018 | − case R_AARCH64_ADD_ABS_LO12_NC: | |
| 1019 | − write32le(ptr, ((read32le(ptr) & 0xffc003ff) | | |
| 1020 | − (val & 0xfff) << 10)); | |
| 1021 | − break; | |
| 1022 | − case R_AARCH64_JUMP26: | |
| 1023 | − case R_AARCH64_CALL26: | |
| 1024 | − /* This check must match the one in build_got_entries, testing | |
| 1025 | − if we really need a PLT slot. */ | |
| 1026 | − if (sym->st_shndx == SHN_UNDEF || | |
| 1027 | − s1->output_type == TCC_OUTPUT_MEMORY) | |
| 1028 | − /* We've put the PLT slot offset into r_addend when generating | |
| 1029 | − it, and that's what we must use as relocation value (adjusted | |
| 1030 | − by section offset of course). */ | |
| 1031 | − val = s1->plt->sh_addr + rel->r_addend; | |
| 1032 | −#ifdef DEBUG_RELOC | |
| 1033 | − printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, | |
| 1034 | − (char *) symtab_section->link->data + sym->st_name); | |
| 1035 | −#endif | |
| 1036 | − if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) | |
| 1037 | − { | |
| 1038 | − tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); | |
| 1039 | − } | |
| 1040 | − write32le(ptr, (0x14000000 | | |
| 1041 | − (uint32_t)(type == R_AARCH64_CALL26) << 31 | | |
| 1042 | − ((val - addr) >> 2 & 0x3ffffff))); | |
| 1043 | − break; | |
| 1044 | − case R_AARCH64_ADR_GOT_PAGE: { | |
| 1045 | − uint64_t off = | |
| 1046 | − (((s1->got->sh_addr + | |
| 1047 | − s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); | |
| 1048 | − if ((off + ((uint64_t)1 << 20)) >> 21) | |
| 1049 | − tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); | |
| 1050 | − write32le(ptr, ((read32le(ptr) & 0x9f00001f) | | |
| 1051 | − (off & 0x1ffffc) << 3 | (off & 3) << 29)); | |
| 1052 | − break; | |
| 1053 | − } | |
| 1054 | − case R_AARCH64_LD64_GOT_LO12_NC: | |
| 1055 | − write32le(ptr, | |
| 1056 | − ((read32le(ptr) & 0xfff803ff) | | |
| 1057 | − ((s1->got->sh_addr + | |
| 1058 | − s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); | |
| 1059 | − break; | |
| 1060 | − case R_AARCH64_COPY: | |
| 1061 | − break; | |
| 1062 | − case R_AARCH64_GLOB_DAT: | |
| 1063 | − case R_AARCH64_JUMP_SLOT: | |
| 1064 | − /* They don't need addend */ | |
| 1065 | −#ifdef DEBUG_RELOC | |
| 1066 | − printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, | |
| 1067 | − val - rel->r_addend, | |
| 1068 | − (char *) symtab_section->link->data + sym->st_name); | |
| 1069 | −#endif | |
| 1070 | − write64le(ptr, val - rel->r_addend); | |
| 1071 | − break; | |
| 1072 | − default: | |
| 1073 | − fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 1074 | − type, (unsigned)addr, ptr, (unsigned)val); | |
| 1075 | − break; | |
| 1076 | −#elif defined(TCC_TARGET_C67) | |
| 1077 | − case R_C60_32: | |
| 1078 | − *(int *)ptr += val; | |
| 1079 | − break; | |
| 1080 | − case R_C60LO16: | |
| 1081 | − { | |
| 1082 | − uint32_t orig; | |
| 1083 | − | |
| 1084 | − /* put the low 16 bits of the absolute address | |
| 1085 | − add to what is already there */ | |
| 1086 | − | |
| 1087 | − orig = ((*(int *)(ptr )) >> 7) & 0xffff; | |
| 1088 | − orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; | |
| 1089 | − | |
| 1090 | − /* patch both at once - assumes always in pairs Low - High */ | |
| 1091 | − | |
| 1092 | − *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); | |
| 1093 | − *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); | |
| 1094 | − } | |
| 1095 | − break; | |
| 1096 | − case R_C60HI16: | |
| 1097 | − break; | |
| 1098 | − default: | |
| 1099 | − fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", | |
| 1100 | − type, (unsigned)addr, ptr, (unsigned)val); | |
| 1101 | − break; | |
| 1102 | −#elif defined(TCC_TARGET_X86_64) | |
| 1103 | − case R_X86_64_64: | |
| 1104 | − if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 1105 | − esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 1106 | − qrel->r_offset = rel->r_offset; | |
| 1107 | − if (esym_index) { | |
| 1108 | − qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); | |
| 1109 | − qrel->r_addend = rel->r_addend; | |
| 1110 | − qrel++; | |
| 1111 | − break; | |
| 1112 | − } else { | |
| 1113 | − qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 1114 | − qrel->r_addend = read64le(ptr) + val; | |
| 1115 | − qrel++; | |
| 1116 | − } | |
| 1117 | − } | |
| 1118 | − add64le(ptr, val); | |
| 1119 | − break; | |
| 1120 | − case R_X86_64_32: | |
| 1121 | − case R_X86_64_32S: | |
| 1122 | − if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 1123 | − /* XXX: this logic may depend on TCC's codegen | |
| 1124 | − now TCC uses R_X86_64_32 even for a 64bit pointer */ | |
| 1125 | − qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 1126 | − /* Use sign extension! */ | |
| 1127 | − qrel->r_addend = (int)read32le(ptr) + val; | |
| 1128 | − qrel++; | |
| 1129 | − } | |
| 1130 | − add32le(ptr, val); | |
| 1131 | − break; | |
| 1132 | − | |
| 1133 | − case R_X86_64_PC32: | |
| 1134 | − if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 1135 | − /* DLL relocation */ | |
| 1136 | − esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 1137 | − if (esym_index) { | |
| 1138 | − qrel->r_offset = rel->r_offset; | |
| 1139 | − qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); | |
| 1140 | − /* Use sign extension! */ | |
| 1141 | − qrel->r_addend = (int)read32le(ptr) + rel->r_addend; | |
| 1142 | − qrel++; | |
| 1143 | − break; | |
| 1144 | − } | |
| 1145 | − } | |
| 1146 | − goto plt32pc32; | |
| 1147 | − | |
| 1148 | − case R_X86_64_PLT32: | |
| 1149 | − /* We've put the PLT slot offset into r_addend when generating | |
| 1150 | − it, and that's what we must use as relocation value (adjusted | |
| 1151 | − by section offset of course). */ | |
| 1152 | − val = s1->plt->sh_addr + rel->r_addend; | |
| 1153 | − /* fallthrough. */ | |
| 1154 | − | |
| 1155 | − plt32pc32: | |
| 1156 | − { | |
| 1157 | − long long diff; | |
| 1158 | − diff = (long long)val - addr; | |
| 1159 | − if (diff < -2147483648LL || diff > 2147483647LL) { | |
| 1160 | − tcc_error("internal error: relocation failed"); | |
| 1161 | − } | |
| 1162 | − add32le(ptr, diff); | |
| 1163 | − } | |
| 1164 | − break; | |
| 1165 | − case R_X86_64_GLOB_DAT: | |
| 1166 | − case R_X86_64_JUMP_SLOT: | |
| 1167 | − /* They don't need addend */ | |
| 1168 | − write64le(ptr, val - rel->r_addend); | |
| 1169 | − break; | |
| 1170 | − case R_X86_64_GOTPCREL: | |
| 1171 | − case R_X86_64_GOTPCRELX: | |
| 1172 | − case R_X86_64_REX_GOTPCRELX: | |
| 1173 | − add32le(ptr, s1->got->sh_addr - addr | |
| 1174 | − + s1->sym_attrs[sym_index].got_offset - 4); | |
| 1175 | − break; | |
| 1176 | − case R_X86_64_GOTTPOFF: | |
| 1177 | − add32le(ptr, val - s1->got->sh_addr); | |
| 1178 | − break; | |
| 1179 | − case R_X86_64_GOT32: | |
| 1180 | − /* we load the got offset */ | |
| 1181 | − add32le(ptr, s1->sym_attrs[sym_index].got_offset); | |
| 1182 | − break; | |
| 1183 | −#ifdef TCC_TARGET_PE | |
| 1184 | − case R_X86_64_RELATIVE: /* handled in pe_relocate_rva() */ | |
| 1185 | − break; | |
| 1186 | −#endif | |
| 1187 | − | |
| 1188 | −#else | |
| 1189 | −#error unsupported processor | |
| 1190 | −#endif | |
| 1191 | − } | |
| 711 | + relocate(s1, rel, type, ptr, addr, val); | |
| 1192 | 712 | } |
| 1193 | 713 | /* if the relocation is allocated, we change its symbol table */ |
| 1194 | 714 | if (sr->sh_flags & SHF_ALLOC) |
| @@ -0,0 +1,99 @@ | ||
| 1 | +#include "tcc.h" | |
| 2 | +#define HAVE_SECTION_RELOC | |
| 3 | + | |
| 4 | +static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ | |
| 5 | + | |
| 6 | +void relocate_init(Section *sr) | |
| 7 | +{ | |
| 8 | + qrel = (ElfW_Rel *) sr->data; | |
| 9 | +} | |
| 10 | + | |
| 11 | +void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | |
| 12 | +{ | |
| 13 | + int sym_index, esym_index; | |
| 14 | + | |
| 15 | + sym_index = ELFW(R_SYM)(rel->r_info); | |
| 16 | + | |
| 17 | + switch (type) { | |
| 18 | + case R_X86_64_64: | |
| 19 | + if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 20 | + esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 21 | + qrel->r_offset = rel->r_offset; | |
| 22 | + if (esym_index) { | |
| 23 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); | |
| 24 | + qrel->r_addend = rel->r_addend; | |
| 25 | + qrel++; | |
| 26 | + break; | |
| 27 | + } else { | |
| 28 | + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 29 | + qrel->r_addend = read64le(ptr) + val; | |
| 30 | + qrel++; | |
| 31 | + } | |
| 32 | + } | |
| 33 | + add64le(ptr, val); | |
| 34 | + break; | |
| 35 | + case R_X86_64_32: | |
| 36 | + case R_X86_64_32S: | |
| 37 | + if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 38 | + /* XXX: this logic may depend on TCC's codegen | |
| 39 | + now TCC uses R_X86_64_32 even for a 64bit pointer */ | |
| 40 | + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 41 | + /* Use sign extension! */ | |
| 42 | + qrel->r_addend = (int)read32le(ptr) + val; | |
| 43 | + qrel++; | |
| 44 | + } | |
| 45 | + add32le(ptr, val); | |
| 46 | + break; | |
| 47 | + | |
| 48 | + case R_X86_64_PC32: | |
| 49 | + if (s1->output_type == TCC_OUTPUT_DLL) { | |
| 50 | + /* DLL relocation */ | |
| 51 | + esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 52 | + if (esym_index) { | |
| 53 | + qrel->r_offset = rel->r_offset; | |
| 54 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); | |
| 55 | + /* Use sign extension! */ | |
| 56 | + qrel->r_addend = (int)read32le(ptr) + rel->r_addend; | |
| 57 | + qrel++; | |
| 58 | + break; | |
| 59 | + } | |
| 60 | + } | |
| 61 | + goto plt32pc32; | |
| 62 | + | |
| 63 | + case R_X86_64_PLT32: | |
| 64 | + /* We've put the PLT slot offset into r_addend when generating | |
| 65 | + it, and that's what we must use as relocation value (adjusted | |
| 66 | + by section offset of course). */ | |
| 67 | + val = s1->plt->sh_addr + rel->r_addend; | |
| 68 | + /* fallthrough. */ | |
| 69 | + | |
| 70 | + plt32pc32: | |
| 71 | + { | |
| 72 | + long long diff; | |
| 73 | + diff = (long long)val - addr; | |
| 74 | + if (diff < -2147483648LL || diff > 2147483647LL) { | |
| 75 | + tcc_error("internal error: relocation failed"); | |
| 76 | + } | |
| 77 | + add32le(ptr, diff); | |
| 78 | + } | |
| 79 | + break; | |
| 80 | + case R_X86_64_GLOB_DAT: | |
| 81 | + case R_X86_64_JUMP_SLOT: | |
| 82 | + /* They don't need addend */ | |
| 83 | + write64le(ptr, val - rel->r_addend); | |
| 84 | + break; | |
| 85 | + case R_X86_64_GOTPCREL: | |
| 86 | + case R_X86_64_GOTPCRELX: | |
| 87 | + case R_X86_64_REX_GOTPCRELX: | |
| 88 | + add32le(ptr, s1->got->sh_addr - addr + | |
| 89 | + s1->sym_attrs[sym_index].got_offset - 4); | |
| 90 | + break; | |
| 91 | + case R_X86_64_GOTTPOFF: | |
| 92 | + add32le(ptr, val - s1->got->sh_addr); | |
| 93 | + break; | |
| 94 | + case R_X86_64_GOT32: | |
| 95 | + /* we load the got offset */ | |
| 96 | + add32le(ptr, s1->sym_attrs[sym_index].got_offset); | |
| 97 | + break; | |
| 98 | + } | |
| 99 | +} | |