1 #ifdef TARGET_DEFS_ONLY
3 #define EM_TCC_TARGET EM_ARM
5 /* relocation type for 32 bit data relocation */
6 #define R_DATA_32 R_ARM_ABS32
7 #define R_DATA_PTR R_ARM_ABS32
8 #define R_JMP_SLOT R_ARM_JUMP_SLOT
9 #define R_GLOB_DAT R_ARM_GLOB_DAT
10 #define R_COPY R_ARM_COPY
11 #define R_RELATIVE R_ARM_RELATIVE
13 #define R_NUM R_ARM_NUM
15 #define ELF_START_ADDR 0x00010000
16 #define ELF_PAGE_SIZE 0x10000
18 #define PCRELATIVE_DLLPLT 1
19 #define RELOCATE_DLLPLT 1
26 #else /* !TARGET_DEFS_ONLY */
30 /* Returns 1 for a code relocation, 0 for a data relocation. For unknown
31 relocations, returns -1. */
32 int code_reloc (int reloc_type
)
36 case R_ARM_MOVW_ABS_NC
:
37 case R_ARM_THM_MOVT_ABS
:
38 case R_ARM_THM_MOVW_ABS_NC
:
50 case R_ARM_MOVW_PREL_NC
:
58 case R_ARM_THM_JUMP24
:
67 /* Returns an enumerator to describe whether and when the relocation needs a
68 GOT and/or PLT entry to be created. See tcc.h for a description of the
70 int gotplt_entry_type (int reloc_type
)
77 return NO_GOTPLT_ENTRY
;
84 case R_ARM_THM_JUMP24
:
86 case R_ARM_MOVW_ABS_NC
:
87 case R_ARM_THM_MOVT_ABS
:
88 case R_ARM_THM_MOVW_ABS_NC
:
95 case R_ARM_MOVW_PREL_NC
:
96 return AUTO_GOTPLT_ENTRY
;
100 return BUILD_GOT_ONLY
;
104 return ALWAYS_GOTPLT_ENTRY
;
109 #ifndef TCC_TARGET_PE
110 ST_FUNC
unsigned create_plt_entry(TCCState
*s1
, unsigned got_offset
, struct sym_attr
*attr
)
112 Section
*plt
= s1
->plt
;
116 /* when building a DLL, GOT entry accesses must be done relative to
117 start of GOT (see x86_64 example above) */
119 /* empty PLT: create PLT0 entry that push address of call site and
120 jump to ld.so resolution routine (GOT + 8) */
121 if (plt
->data_offset
== 0) {
122 p
= section_ptr_add(plt
, 20);
123 write32le(p
, 0xe52de004); /* push {lr} */
124 write32le(p
+4, 0xe59fe004); /* ldr lr, [pc, #4] */
125 write32le(p
+8, 0xe08fe00e); /* add lr, pc, lr */
126 write32le(p
+12, 0xe5bef008); /* ldr pc, [lr, #8]! */
127 /* p+16 is set in relocate_plt */
129 plt_offset
= plt
->data_offset
;
131 if (attr
->plt_thumb_stub
) {
132 p
= section_ptr_add(plt
, 4);
133 write32le(p
, 0x4778); /* bx pc */
134 write32le(p
+2, 0x46c0); /* nop */
136 p
= section_ptr_add(plt
, 16);
137 /* save GOT offset for relocate_plt */
138 write32le(p
+ 4, got_offset
);
142 /* relocate the PLT: compute addresses and offsets in the PLT now that final
143 address for PLT and GOT are known (see fill_program_header) */
144 ST_FUNC
void relocate_plt(TCCState
*s1
)
152 p_end
= p
+ s1
->plt
->data_offset
;
155 int x
= s1
->got
->sh_addr
- s1
->plt
->sh_addr
- 12;
156 write32le(s1
->plt
->data
+ 16, x
- 4);
159 unsigned off
= x
+ read32le(p
+ 4) + (s1
->plt
->data
- p
) + 4;
160 if (read32le(p
) == 0x46c04778) /* PLT Thumb stub present */
162 write32le(p
, 0xe28fc200 | ((off
>> 28) & 0xf)); // add ip, pc, #0xN0000000
163 write32le(p
+ 4, 0xe28cc600 | ((off
>> 20) & 0xff)); // add ip, pc, #0xNN00000
164 write32le(p
+ 8, 0xe28cca00 | ((off
>> 12) & 0xff)); // add ip, ip, #0xNN000
165 write32le(p
+ 12, 0xe5bcf000 | (off
& 0xfff)); // ldr pc, [ip, #0xNNN]!
170 if (s1
->got
->relocplt
) {
171 int mem
= s1
->output_type
== TCC_OUTPUT_MEMORY
;
175 for_each_elem(s1
->got
->relocplt
, 0, rel
, ElfW_Rel
) {
176 int sym_index
= ELFW(R_SYM
)(rel
->r_info
);
177 ElfW(Sym
) *sym
= &((ElfW(Sym
) *)symtab_section
->data
)[sym_index
];
178 write32le(p
+ rel
->r_offset
, mem
? sym
->st_value
: s1
->plt
->sh_addr
);
184 void relocate(TCCState
*s1
, ElfW_Rel
*rel
, int type
, unsigned char *ptr
, addr_t addr
, addr_t val
)
187 int sym_index
, esym_index
;
189 sym_index
= ELFW(R_SYM
)(rel
->r_info
);
190 sym
= &((ElfW(Sym
) *)symtab_section
->data
)[sym_index
];
198 int x
, is_thumb
, is_call
, h
, blx_avail
, is_bl
, th_ko
;
199 x
= (*(int *) ptr
) & 0xffffff;
201 printf ("reloc %d: x=0x%x val=0x%x ", type
, x
, val
);
203 (*(int *)ptr
) &= 0xff000000;
207 blx_avail
= (TCC_CPU_VERSION
>= 5);
209 is_bl
= (*(unsigned *) ptr
) >> 24 == 0xeb;
210 is_call
= (type
== R_ARM_CALL
|| (type
== R_ARM_PC24
&& is_bl
));
213 printf (" newx=0x%x name=%s\n", x
,
214 (char *) symtab_section
->link
->data
+ sym
->st_name
);
217 th_ko
= (x
& 3) && (!blx_avail
|| !is_call
);
218 if (th_ko
|| x
>= 0x2000000 || x
< -0x2000000)
219 tcc_error("can't relocate value at %x,%d",addr
, type
);
222 /* Only reached if blx is avail and it is a call */
225 (*(int *)ptr
) = 0xfa << 24; /* bl -> blx */
230 /* Since these relocations only concern Thumb-2 and blx instruction was
231 introduced before Thumb-2, we can assume blx is available and not
234 case R_ARM_THM_JUMP24
:
236 int x
, hi
, lo
, s
, j1
, j2
, i1
, i2
, imm10
, imm11
;
237 int to_thumb
, is_call
, to_plt
, blx_bit
= 1 << 12;
241 if (sym
->st_shndx
== SHN_UNDEF
&&
242 ELFW(ST_BIND
)(sym
->st_info
) == STB_WEAK
)
245 /* Get initial offset */
246 hi
= (*(uint16_t *)ptr
);
247 lo
= (*(uint16_t *)(ptr
+2));
255 x
= (s
<< 24) | (i1
<< 23) | (i2
<< 22) |
256 (imm10
<< 12) | (imm11
<< 1);
260 /* Relocation infos */
263 to_plt
= (val
>= plt
->sh_addr
) &&
264 (val
< plt
->sh_addr
+ plt
->data_offset
);
265 is_call
= (type
== R_ARM_THM_PC22
);
267 if (!to_thumb
&& !to_plt
&& !is_call
) {
270 char *name
, buf
[1024];
273 name
= (char *) symtab_section
->link
->data
+ sym
->st_name
;
274 text
= s1
->sections
[sym
->st_shndx
];
275 /* Modify reloc to target a thumb stub to switch to ARM */
276 snprintf(buf
, sizeof(buf
), "%s_from_thumb", name
);
277 index
= put_elf_sym(symtab_section
,
278 text
->data_offset
+ 1,
279 sym
->st_size
, sym
->st_info
, 0,
282 val
= text
->data_offset
+ 1;
283 rel
->r_info
= ELFW(R_INFO
)(index
, type
);
284 /* Create a thumb stub function to switch to ARM mode */
285 put_elf_reloc(symtab_section
, text
,
286 text
->data_offset
+ 4, R_ARM_JUMP24
,
288 p
= section_ptr_add(text
, 8);
289 write32le(p
, 0x4778); /* bx pc */
290 write32le(p
+2, 0x46c0); /* nop */
291 write32le(p
+4, 0xeafffffe); /* b $sym */
294 /* Compute final offset */
296 if (!to_thumb
&& is_call
) {
297 blx_bit
= 0; /* bl -> blx */
298 x
= (x
+ 3) & -4; /* Compute offset from aligned PC */
301 /* Check that relocation is possible
302 * offset must not be out of range
303 * if target is to be entered in arm mode:
305 - instruction must be a call (bl) or a jump to PLT */
306 if (!to_thumb
|| x
>= 0x1000000 || x
< -0x1000000)
307 if (to_thumb
|| (val
& 2) || (!is_call
&& !to_plt
))
308 tcc_error("can't relocate value at %x,%d",addr
, type
);
310 /* Compute and store final offset */
316 imm10
= (x
>> 12) & 0x3ff;
317 imm11
= (x
>> 1) & 0x7ff;
318 (*(uint16_t *)ptr
) = (uint16_t) ((hi
& 0xf800) |
320 (*(uint16_t *)(ptr
+2)) = (uint16_t) ((lo
& 0xc000) |
321 (j1
<< 13) | blx_bit
| (j2
<< 11) |
326 case R_ARM_MOVW_ABS_NC
:
329 if (type
== R_ARM_MOVT_ABS
)
332 imm4
= (val
>> 12) & 0xf;
333 x
= (imm4
<< 16) | imm12
;
334 if (type
== R_ARM_THM_MOVT_ABS
)
340 case R_ARM_MOVT_PREL
:
341 case R_ARM_MOVW_PREL_NC
:
343 int insn
= *(int *)ptr
;
344 int addend
= ((insn
>> 4) & 0xf000) | (insn
& 0xfff);
346 addend
= (addend
^ 0x8000) - 0x8000;
347 val
+= addend
- addr
;
348 if (type
== R_ARM_MOVT_PREL
)
350 *(int *)ptr
= (insn
& 0xfff0f000) |
351 ((val
& 0xf000) << 4) | (val
& 0xfff);
354 case R_ARM_THM_MOVT_ABS
:
355 case R_ARM_THM_MOVW_ABS_NC
:
357 int x
, i
, imm4
, imm3
, imm8
;
358 if (type
== R_ARM_THM_MOVT_ABS
)
361 imm3
= (val
>> 8) & 0x7;
363 imm4
= (val
>> 12) & 0xf;
364 x
= (imm3
<< 28) | (imm8
<< 16) | (i
<< 10) | imm4
;
365 if (type
== R_ARM_THM_MOVT_ABS
)
374 x
= (*(int *)ptr
) & 0x7fffffff;
375 (*(int *)ptr
) &= 0x80000000;
378 if((x
^(x
>>1))&0x40000000)
379 tcc_error("can't relocate value at %x,%d",addr
, type
);
380 (*(int *)ptr
) |= x
& 0x7fffffff;
385 if (s1
->output_type
== TCC_OUTPUT_DLL
) {
386 esym_index
= get_sym_attr(s1
, sym_index
, 0)->dyn_index
;
387 qrel
->r_offset
= rel
->r_offset
;
389 qrel
->r_info
= ELFW(R_INFO
)(esym_index
, R_ARM_ABS32
);
393 qrel
->r_info
= ELFW(R_INFO
)(0, R_ARM_RELATIVE
);
400 *(int *)ptr
+= val
- addr
;
403 *(int *)ptr
+= s1
->got
->sh_addr
- addr
;
406 *(int *)ptr
+= val
- s1
->got
->sh_addr
;
409 /* we load the got offset */
410 *(int *)ptr
+= get_sym_attr(s1
, sym_index
, 0)->got_offset
;
413 /* we load the pc relative got offset */
414 *(int *)ptr
+= s1
->got
->sh_addr
+
415 get_sym_attr(s1
, sym_index
, 0)->got_offset
-
421 /* trade Thumb support for ARMv4 support */
422 if ((0x0ffffff0 & *(int*)ptr
) == 0x012FFF10)
423 *(int*)ptr
^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
426 case R_ARM_JUMP_SLOT
:
427 *(addr_t
*)ptr
= val
;
430 /* Nothing to do. Normally used to indicate a dependency
431 on a certain symbol (like for exception handling under EABI). */
435 add32le(ptr
, val
- s1
->pe_imagebase
);
440 fprintf(stderr
,"FIXME: handle reloc type %d at %x [%p] to %x\n",
441 type
, (unsigned)addr
, ptr
, (unsigned)val
);
446 #endif /* !TARGET_DEFS_ONLY */