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
12 #define R_NUM R_ARM_NUM
14 #define ELF_START_ADDR 0x00008000
15 #define ELF_PAGE_SIZE 0x1000
17 #define HAVE_SECTION_RELOC
24 #else /* !TARGET_DEFS_ONLY */
28 ST_DATA
struct reloc_info relocs_info
[R_NUM
] = {
29 INIT_RELOC_INFO (R_ARM_PC24
, 1, AUTO_GOTPLT_ENTRY
, 0)
30 INIT_RELOC_INFO (R_ARM_CALL
, 1, AUTO_GOTPLT_ENTRY
, 0)
31 INIT_RELOC_INFO (R_ARM_JUMP24
, 1, AUTO_GOTPLT_ENTRY
, 0)
32 INIT_RELOC_INFO (R_ARM_PLT32
, 1, ALWAYS_GOTPLT_ENTRY
, 0)
33 INIT_RELOC_INFO (R_ARM_THM_PC22
, 1, AUTO_GOTPLT_ENTRY
, 0)
34 INIT_RELOC_INFO (R_ARM_THM_JUMP24
, 1, AUTO_GOTPLT_ENTRY
, 0)
35 INIT_RELOC_INFO (R_ARM_MOVT_ABS
, 0, AUTO_GOTPLT_ENTRY
, 0)
36 INIT_RELOC_INFO (R_ARM_MOVW_ABS_NC
, 0, AUTO_GOTPLT_ENTRY
, 0)
37 INIT_RELOC_INFO (R_ARM_THM_MOVT_ABS
, 0, AUTO_GOTPLT_ENTRY
, 0)
38 INIT_RELOC_INFO (R_ARM_THM_MOVW_ABS_NC
, 0, AUTO_GOTPLT_ENTRY
, 0)
39 INIT_RELOC_INFO (R_ARM_PREL31
, 1, AUTO_GOTPLT_ENTRY
, 0)
40 INIT_RELOC_INFO (R_ARM_ABS32
, 0, AUTO_GOTPLT_ENTRY
, 0)
41 INIT_RELOC_INFO (R_ARM_REL32
, 0, AUTO_GOTPLT_ENTRY
, 0)
42 INIT_RELOC_INFO (R_ARM_GOTPC
, 0, BUILD_GOT_ONLY
, 0)
43 INIT_RELOC_INFO (R_ARM_GOTOFF
, 0, BUILD_GOT_ONLY
, 0)
44 INIT_RELOC_INFO (R_ARM_GOT32
, 0, ALWAYS_GOTPLT_ENTRY
, 0)
45 INIT_RELOC_INFO (R_ARM_COPY
, 0, NO_GOTPLT_ENTRY
, 0)
46 INIT_RELOC_INFO (R_ARM_V4BX
, 1, AUTO_GOTPLT_ENTRY
, 0)
47 INIT_RELOC_INFO (R_ARM_GLOB_DAT
, 0, NO_GOTPLT_ENTRY
, 0)
48 INIT_RELOC_INFO (R_ARM_JUMP_SLOT
, 1, NO_GOTPLT_ENTRY
, 0)
49 INIT_RELOC_INFO (R_ARM_NONE
, 0, NO_GOTPLT_ENTRY
, 0)
52 void relocate_init(Section
*sr
) {}
54 void relocate(TCCState
*s1
, ElfW_Rel
*rel
, int type
, char *ptr
, addr_t addr
, addr_t val
)
59 sym_index
= ELFW(R_SYM
)(rel
->r_info
);
60 sym
= &((ElfW(Sym
) *)symtab_section
->data
)[sym_index
];
68 int x
, is_thumb
, is_call
, h
, blx_avail
, is_bl
, th_ko
;
69 x
= (*(int *) ptr
) & 0xffffff;
71 printf ("reloc %d: x=0x%x val=0x%x ", type
, x
, val
);
73 (*(int *)ptr
) &= 0xff000000;
77 blx_avail
= (TCC_ARM_VERSION
>= 5);
79 is_bl
= (*(unsigned *) ptr
) >> 24 == 0xeb;
80 is_call
= (type
== R_ARM_CALL
|| (type
== R_ARM_PC24
&& is_bl
));
83 printf (" newx=0x%x name=%s\n", x
,
84 (char *) symtab_section
->link
->data
+ sym
->st_name
);
87 th_ko
= (x
& 3) && (!blx_avail
|| !is_call
);
88 if (th_ko
|| x
>= 0x2000000 || x
< -0x2000000)
89 tcc_error("can't relocate value at %x,%d",addr
, type
);
92 /* Only reached if blx is avail and it is a call */
95 (*(int *)ptr
) = 0xfa << 24; /* bl -> blx */
100 /* Since these relocations only concern Thumb-2 and blx instruction was
101 introduced before Thumb-2, we can assume blx is available and not
104 case R_ARM_THM_JUMP24
:
106 int x
, hi
, lo
, s
, j1
, j2
, i1
, i2
, imm10
, imm11
;
107 int to_thumb
, is_call
, to_plt
, blx_bit
= 1 << 12;
111 if (sym
->st_shndx
== SHN_UNDEF
&&
112 ELFW(ST_BIND
)(sym
->st_info
) == STB_WEAK
)
115 /* Get initial offset */
116 hi
= (*(uint16_t *)ptr
);
117 lo
= (*(uint16_t *)(ptr
+2));
125 x
= (s
<< 24) | (i1
<< 23) | (i2
<< 22) |
126 (imm10
<< 12) | (imm11
<< 1);
130 /* Relocation infos */
133 to_plt
= (val
>= plt
->sh_addr
) &&
134 (val
< plt
->sh_addr
+ plt
->data_offset
);
135 is_call
= (type
== R_ARM_THM_PC22
);
137 if (!to_thumb
&& !to_plt
&& !is_call
) {
140 char *name
, buf
[1024];
141 Section
*text_section
;
143 name
= (char *) symtab_section
->link
->data
+ sym
->st_name
;
144 text_section
= s1
->sections
[sym
->st_shndx
];
145 /* Modify reloc to target a thumb stub to switch to ARM */
146 snprintf(buf
, sizeof(buf
), "%s_from_thumb", name
);
147 index
= put_elf_sym(symtab_section
,
148 text_section
->data_offset
+ 1,
149 sym
->st_size
, sym
->st_info
, 0,
152 val
= text_section
->data_offset
+ 1;
153 rel
->r_info
= ELFW(R_INFO
)(index
, type
);
154 /* Create a thumb stub function to switch to ARM mode */
155 put_elf_reloc(symtab_section
, text_section
,
156 text_section
->data_offset
+ 4, R_ARM_JUMP24
,
158 p
= section_ptr_add(text_section
, 8);
159 write32le(p
, 0x4778); /* bx pc */
160 write32le(p
+2, 0x46c0); /* nop */
161 write32le(p
+4, 0xeafffffe); /* b $sym */
164 /* Compute final offset */
166 if (!to_thumb
&& is_call
) {
167 blx_bit
= 0; /* bl -> blx */
168 x
= (x
+ 3) & -4; /* Compute offset from aligned PC */
171 /* Check that relocation is possible
172 * offset must not be out of range
173 * if target is to be entered in arm mode:
175 - instruction must be a call (bl) or a jump to PLT */
176 if (!to_thumb
|| x
>= 0x1000000 || x
< -0x1000000)
177 if (to_thumb
|| (val
& 2) || (!is_call
&& !to_plt
))
178 tcc_error("can't relocate value at %x,%d",addr
, type
);
180 /* Compute and store final offset */
186 imm10
= (x
>> 12) & 0x3ff;
187 imm11
= (x
>> 1) & 0x7ff;
188 (*(uint16_t *)ptr
) = (uint16_t) ((hi
& 0xf800) |
190 (*(uint16_t *)(ptr
+2)) = (uint16_t) ((lo
& 0xc000) |
191 (j1
<< 13) | blx_bit
| (j2
<< 11) |
196 case R_ARM_MOVW_ABS_NC
:
199 if (type
== R_ARM_MOVT_ABS
)
202 imm4
= (val
>> 12) & 0xf;
203 x
= (imm4
<< 16) | imm12
;
204 if (type
== R_ARM_THM_MOVT_ABS
)
210 case R_ARM_THM_MOVT_ABS
:
211 case R_ARM_THM_MOVW_ABS_NC
:
213 int x
, i
, imm4
, imm3
, imm8
;
214 if (type
== R_ARM_THM_MOVT_ABS
)
217 imm3
= (val
>> 8) & 0x7;
219 imm4
= (val
>> 12) & 0xf;
220 x
= (imm3
<< 28) | (imm8
<< 16) | (i
<< 10) | imm4
;
221 if (type
== R_ARM_THM_MOVT_ABS
)
230 x
= (*(int *)ptr
) & 0x7fffffff;
231 (*(int *)ptr
) &= 0x80000000;
234 if((x
^(x
>>1))&0x40000000)
235 tcc_error("can't relocate value at %x,%d",addr
, type
);
236 (*(int *)ptr
) |= x
& 0x7fffffff;
242 *(int *)ptr
+= val
- addr
;
245 *(int *)ptr
+= s1
->got
->sh_addr
- addr
;
248 *(int *)ptr
+= val
- s1
->got
->sh_addr
;
251 /* we load the got offset */
252 *(int *)ptr
+= s1
->sym_attrs
[sym_index
].got_offset
;
257 /* trade Thumb support for ARMv4 support */
258 if ((0x0ffffff0 & *(int*)ptr
) == 0x012FFF10)
259 *(int*)ptr
^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */
262 case R_ARM_JUMP_SLOT
:
263 *(addr_t
*)ptr
= val
;
266 /* Nothing to do. Normally used to indicate a dependency
267 on a certain symbol (like for exception handling under EABI). */
270 fprintf(stderr
,"FIXME: handle reloc type %x at %x [%p] to %x\n",
271 type
, (unsigned)addr
, ptr
, (unsigned)val
);
276 #endif /* !TARGET_DEFS_ONLY */