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
8080
8181 CORE_FILES = tcc.c libtcc.c tccpp.c tccgen.c tccelf.c tccasm.c tccrun.c
8282 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
84−WIN32_FILES = $(CORE_FILES) i386-gen.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
86−WINCE_FILES = $(CORE_FILES) arm-gen.c tccpe.c
87−X86_64_FILES = $(CORE_FILES) x86_64-gen.c i386-asm.c x86_64-asm.h
88−ARM_FILES = $(CORE_FILES) arm-gen.c
89−ARM64_FILES = $(CORE_FILES) arm64-gen.c
90−C67_FILES = $(CORE_FILES) c67-gen.c tcccoff.c
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-link.c i386-asm.c i386-asm.h i386-tok.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 arm-link.c tccpe.c
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 arm-link.c
89+ARM64_FILES = $(CORE_FILES) arm64-gen.c arm64-link.c
90+C67_FILES = $(CORE_FILES) c67-gen.c c67-link.c tcccoff.c
9191
9292 ifdef CONFIG_WIN32
9393 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+
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+}
arm64-link.c+104−0
@@ -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+}
c67-link.c+35−0
@@ -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+}
i386-link.c+90−0
@@ -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+}
libtcc.c+5−0
@@ -41,18 +41,23 @@ ST_DATA struct TCCState *tcc_state; · 40 unmodified lines
4141 #include "tccrun.c"
4242 #ifdef TCC_TARGET_I386
4343 #include "i386-gen.c"
44+#include "i386-link.c"
4445 #endif
4546 #ifdef TCC_TARGET_ARM
4647 #include "arm-gen.c"
48+#include "arm-link.c"
4749 #endif
4850 #ifdef TCC_TARGET_ARM64
4951 #include "arm64-gen.c"
52+#include "arm64-link.c"
5053 #endif
5154 #ifdef TCC_TARGET_C67
5255 #include "c67-gen.c"
56+#include "c67-link.c"
5357 #endif
5458 #ifdef TCC_TARGET_X86_64
5559 #include "x86_64-gen.c"
60+#include "x86_64-link.c"
5661 #endif
5762 #ifdef CONFIG_TCC_ASM
5863 #include "tccasm.c"
tcc.h+5−0
@@ -1485,6 +1485,11 @@ ST_FUNC void gen_clear_cache(void); · 1484 unmodified lines
14851485 #ifdef TCC_TARGET_C67
14861486 #endif
14871487
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+
14881493 /* ------------ tcccoff.c ------------ */
14891494
14901495 #ifdef TCC_TARGET_COFF
tccelf.c+2−482
@@ -694,11 +694,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 693 unmodified lines
694694 int type, sym_index;
695695 unsigned char *ptr;
696696 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
701697
698+ relocate_init(sr);
702699 for_each_elem(sr, 0, rel, ElfW_Rel) {
703700 ptr = s->data + rel->r_offset;
704701
@@ -711,484 +708,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 6 unmodified lines
711708 type = ELFW(R_TYPE)(rel->r_info);
712709 addr = s->sh_addr + rel->r_offset;
713710
714− /* CPU specific */
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− }
711+ relocate(s1, rel, type, ptr, addr, val);
1192712 }
1193713 /* if the relocation is allocated, we change its symbol table */
1194714 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+
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+}

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