Do section relocation in architecture backend
[tinycc.git] / x86_64-link.c
blob2a9e9b0324a38bc4bdc84fdd4e4789f29a875db9
1 #include "tcc.h"
2 #define HAVE_SECTION_RELOC
4 static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
6 void relocate_init(Section *sr)
8 qrel = (ElfW_Rel *) sr->data;
11 void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
13 int sym_index, esym_index;
15 sym_index = ELFW(R_SYM)(rel->r_info);
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++;
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++;
45 add32le(ptr, val);
46 break;
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;
61 goto plt32pc32;
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. */
70 plt32pc32:
72 long long diff;
73 diff = (long long)val - addr;
74 if (diff < -2147483648LL || diff > 2147483647LL) {
75 tcc_error("internal error: relocation failed");
77 add32le(ptr, diff);
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;