History

Do section relocation in architecture backend

Thomas Preud'homme committed 10 years ago

Commit cb273fd1 parent 60374d09 files · +552 −490Browse files

Unified · Split

9 files
  1. Makefile +8 −8
  2. arm-link.c +204 −0
  3. arm64-link.c +104 −0
  4. c67-link.c +35 −0
  5. i386-link.c +90 −0
  6. libtcc.c +5 −0
  7. tcc.h +5 −0
  8. tccelf.c +2 −482
  9. x86_64-link.c +99 −0
Makefile+8−8
@@ -80,14 +80,14 @@ C67_CROSS = c67-tcc$(EXESUF) · 79 unmodified lines
80 80
81CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c81CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
82CORE_FILES += tcc.h config.h libtcc.h tcctok.h82CORE_FILES += tcc.h config.h libtcc.h tcctok.h
83I386_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h83I386_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h
84WIN32_FILES = $(CORE_FILES) i386-gen.c i386-asm.c i386-asm.h i386-tok.h tccpe.c84WIN32_FILES = $(CORE_FILES) i386-gen.c i386-link.c i386-asm.c i386-asm.h i386-tok.h tccpe.c
85WIN64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h tccpe.c85WIN64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h tccpe.c
86WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c86WINCE_FILES = $(CORE_FILES) arm-gen.c arm-link.c tccpe.c
87X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h87X86_64_FILES = $(CORE_FILES) x86_64-gen.c x86_64-link.c i386-asm.c x86_64-asm.h
88ARM_FILES = $(CORE_FILES) arm-gen.c88ARM_FILES = $(CORE_FILES) arm-gen.c arm-link.c
89ARM64_FILES = $(CORE_FILES) arm64-gen.c89ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
90C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c90C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
91 91
92ifdef CONFIG_WIN3292ifdef CONFIG_WIN32
93 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) $(LIBTCC)93 PROGS+=tiny_impdef$(EXESUF) tiny_libmaker$(EXESUF) $(LIBTCC)
arm-link.c+204−0
@@ -0,0 +1,204 @@
1#include "tcc.h"
2#define HAVE_SECTION_RELOC
3
4void relocate_init(Section *sr) {}
5
6void 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}
arm64-link.c+104−0
@@ -0,0 +1,104 @@
1#include "tcc.h"
2#define HAVE_SECTION_RELOC
3
4void relocate_init(Section *sr) {}
5
6void 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}
c67-link.c+35−0
@@ -0,0 +1,35 @@
1#include "tcc.h"
2#define HAVE_SECTION_RELOC
3
4void relocate_init(Section *sr) {}
5
6void 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}
i386-link.c+90−0
@@ -0,0 +1,90 @@
1#include "tcc.h"
2#define HAVE_SECTION_RELOC
3
4static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
5
6void relocate_init(Section *sr)
7{
8 qrel = (ElfW_Rel *) sr->data;
9}
10
11void 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}
libtcc.c+5−0
@@ -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_I38642#ifdef TCC_TARGET_I386
43#include "i386-gen.c"43#include "i386-gen.c"
44#include "i386-link.c"
44#endif45#endif
45#ifdef TCC_TARGET_ARM46#ifdef TCC_TARGET_ARM
46#include "arm-gen.c"47#include "arm-gen.c"
48#include "arm-link.c"
47#endif49#endif
48#ifdef TCC_TARGET_ARM6450#ifdef TCC_TARGET_ARM64
49#include "arm64-gen.c"51#include "arm64-gen.c"
52#include "arm64-link.c"
50#endif53#endif
51#ifdef TCC_TARGET_C6754#ifdef TCC_TARGET_C67
52#include "c67-gen.c"55#include "c67-gen.c"
56#include "c67-link.c"
53#endif57#endif
54#ifdef TCC_TARGET_X86_6458#ifdef TCC_TARGET_X86_64
55#include "x86_64-gen.c"59#include "x86_64-gen.c"
60#include "x86_64-link.c"
56#endif61#endif
57#ifdef CONFIG_TCC_ASM62#ifdef CONFIG_TCC_ASM
58#include "tccasm.c"63#include "tccasm.c"
tcc.h+5−0
@@ -1485,6 +1485,11 @@ ST_FUNC void gen_clear_cache(void); · 1484 unmodified lines
1485#ifdef TCC_TARGET_C671485#ifdef TCC_TARGET_C67
1486#endif1486#endif
1487 1487
1488/* ------------ xxx-link.c ------------ */
1489
1490ST_FUNC void relocate_init(Section *sr);
1491ST_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_COFF1495#ifdef TCC_TARGET_COFF
tccelf.c+2−482
@@ -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)
x86_64-link.c+99−0
@@ -0,0 +1,99 @@
1#include "tcc.h"
2#define HAVE_SECTION_RELOC
3
4static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
5
6void relocate_init(Section *sr)
7{
8 qrel = (ElfW_Rel *) sr->data;
9}
10
11void 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}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t