Do section relocation in architecture backend
[tinycc.git] / arm-link.c
blob00332e0828965e70fffe0f23bcaecee382793a09
1 #include "tcc.h"
2 #define HAVE_SECTION_RELOC
4 void relocate_init(Section *sr) {}
6 void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
8 ElfW(Sym) *sym;
9 int sym_index;
11 sym_index = ELFW(R_SYM)(rel->r_info);
12 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
14 switch(type) {
15 case R_ARM_PC24:
16 case R_ARM_CALL:
17 case R_ARM_JUMP24:
18 case R_ARM_PLT32:
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 */
52 (*(int *) ptr) |= x;
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:
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;
65 /* weak reference */
66 if (sym->st_shndx == SHN_UNDEF &&
67 ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
68 return;
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;
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);
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 */
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);
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);
124 return;
125 case R_ARM_MOVT_ABS:
126 case R_ARM_MOVW_ABS_NC:
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;
139 return;
140 case R_ARM_THM_MOVT_ABS:
141 case R_ARM_THM_MOVW_ABS_NC:
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;
156 return;
157 case R_ARM_PREL31:
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;
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;