Unified · Split
| @@ -80,14 +80,14 @@ C67_CROSS = c67-tcc$(EXESUF) · 79 unmodified lines | |||
| 80 | 80 | ||
| 81 | CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c | 81 | CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c |
| 82 | CORE_FILES += tcc.h config.h libtcc.h tcctok.h | 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 | 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-asm.c i386-asm.h i386-tok.h tccpe.c | 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 i386-asm.c x86_64-asm.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 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 i386-asm.c x86_64-asm.h | 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 | 88 | ARM_FILES = $(CORE_FILES) arm-gen.c arm-link.c |
| 89 | ARM64_FILES = $(CORE_FILES) arm64-gen.c | 89 | ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c |
| 90 | C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c | 90 | C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c |
| 91 | 91 | ||
| 92 | ifdef CONFIG_WIN32 | 92 | ifdef CONFIG_WIN32 |
| 93 | PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) $(LIBTCC) | 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 | #include "tccrun.c" | 41 | #include "tccrun.c" |
| 42 | #ifdef TCC_TARGET_I386 | 42 | #ifdef TCC_TARGET_I386 |
| 43 | #include "i386-gen.c" | 43 | #include "i386-gen.c" |
| 44 | #include "i386-link.c" | ||
| 44 | #endif | 45 | #endif |
| 45 | #ifdef TCC_TARGET_ARM | 46 | #ifdef TCC_TARGET_ARM |
| 46 | #include "arm-gen.c" | 47 | #include "arm-gen.c" |
| 48 | #include "arm-link.c" | ||
| 47 | #endif | 49 | #endif |
| 48 | #ifdef TCC_TARGET_ARM64 | 50 | #ifdef TCC_TARGET_ARM64 |
| 49 | #include "arm64-gen.c" | 51 | #include "arm64-gen.c" |
| 52 | #include "arm64-link.c" | ||
| 50 | #endif | 53 | #endif |
| 51 | #ifdef TCC_TARGET_C67 | 54 | #ifdef TCC_TARGET_C67 |
| 52 | #include "c67-gen.c" | 55 | #include "c67-gen.c" |
| 56 | #include "c67-link.c" | ||
| 53 | #endif | 57 | #endif |
| 54 | #ifdef TCC_TARGET_X86_64 | 58 | #ifdef TCC_TARGET_X86_64 |
| 55 | #include "x86_64-gen.c" | 59 | #include "x86_64-gen.c" |
| 60 | #include "x86_64-link.c" | ||
| 56 | #endif | 61 | #endif |
| 57 | #ifdef CONFIG_TCC_ASM | 62 | #ifdef CONFIG_TCC_ASM |
| 58 | #include "tccasm.c" | 63 | #include "tccasm.c" |
| @@ -1485,6 +1485,11 @@ ST_FUNC void gen_clear_cache(void); · 1484 unmodified lines | |||
| 1485 | #ifdef TCC_TARGET_C67 | 1485 | #ifdef TCC_TARGET_C67 |
| 1486 | #endif | 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 | /* ------------ tcccoff.c ------------ */ | 1493 | /* ------------ tcccoff.c ------------ */ |
| 1489 | 1494 | ||
| 1490 | #ifdef TCC_TARGET_COFF | 1495 | #ifdef TCC_TARGET_COFF |
| @@ -694,11 +694,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 693 unmodified lines | |||
| 694 | int type, sym_index; | 694 | int type, sym_index; |
| 695 | unsigned char *ptr; | 695 | unsigned char *ptr; |
| 696 | addr_t val, addr; | 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 | for_each_elem(sr, 0, rel, ElfW_Rel) { | 699 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
| 703 | ptr = s->data + rel->r_offset; | 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 | type = ELFW(R_TYPE)(rel->r_info); | 708 | type = ELFW(R_TYPE)(rel->r_info); |
| 712 | addr = s->sh_addr + rel->r_offset; | 709 | addr = s->sh_addr + rel->r_offset; |
| 713 | 710 | ||
| 714 | /* CPU specific */ | 711 | relocate(s1, rel, type, ptr, addr, val); |
| 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 | } | ||
| 1192 | } | 712 | } |
| 1193 | /* if the relocation is allocated, we change its symbol table */ | 713 | /* if the relocation is allocated, we change its symbol table */ |
| 1194 | if (sr->sh_flags & SHF_ALLOC) | 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 | } | ||