Use functions to get relocation info
[tinycc/jakubkaszycki.git] / x86_64-link.c
blob92404e43caf65dd9a1ad122d88c2a3b5bda243f8
1 #ifdef TARGET_DEFS_ONLY
3 #define EM_TCC_TARGET EM_X86_64
5 /* relocation type for 32 bit data relocation */
6 #define R_DATA_32 R_X86_64_32
7 #define R_DATA_PTR R_X86_64_64
8 #define R_JMP_SLOT R_X86_64_JUMP_SLOT
9 #define R_GLOB_DAT R_X86_64_GLOB_DAT
10 #define R_COPY R_X86_64_COPY
12 #define R_NUM R_X86_64_NUM
14 #define ELF_START_ADDR 0x400000
15 #define ELF_PAGE_SIZE 0x200000
17 #define HAVE_SECTION_RELOC
18 #define PCRELATIVE_DLLPLT 1
20 #else /* !TARGET_DEFS_ONLY */
22 #include "tcc.h"
24 /* Returns 1 for a code relocation, 0 for a data relocation. For unknown
25 relocations, returns -1. */
26 int code_reloc (int reloc_type)
28 switch (reloc_type) {
29 case R_X86_64_32:
30 case R_X86_64_32S:
31 case R_X86_64_64:
32 case R_X86_64_GOTPCREL:
33 case R_X86_64_GOTPCRELX:
34 case R_X86_64_REX_GOTPCRELX:
35 case R_X86_64_GOTTPOFF:
36 case R_X86_64_GOT32:
37 case R_X86_64_GLOB_DAT:
38 case R_X86_64_COPY:
39 return 0;
41 case R_X86_64_PC32:
42 case R_X86_64_PLT32:
43 case R_X86_64_JUMP_SLOT:
44 return 1;
47 tcc_error ("Unknown relocation type: %d", reloc_type);
48 return -1;
51 /* Returns an enumerator to describe wether and when the relocation needs a
52 GOT and/or PLT entry to be created. See tcc.h for a description of the
53 different values. */
54 int gotplt_entry_type (int reloc_type)
56 switch (reloc_type) {
57 case R_X86_64_GLOB_DAT:
58 case R_X86_64_JUMP_SLOT:
59 case R_X86_64_COPY:
60 return NO_GOTPLT_ENTRY;
62 case R_X86_64_32:
63 case R_X86_64_32S:
64 case R_X86_64_64:
65 case R_X86_64_PC32:
66 return AUTO_GOTPLT_ENTRY;
68 case R_X86_64_GOTTPOFF:
69 return BUILD_GOT_ONLY;
71 case R_X86_64_GOT32:
72 case R_X86_64_GOTPCREL:
73 case R_X86_64_GOTPCRELX:
74 case R_X86_64_REX_GOTPCRELX:
75 case R_X86_64_PLT32:
76 return ALWAYS_GOTPLT_ENTRY;
79 tcc_error ("Unknown relocation type: %d", reloc_type);
80 return -1;
83 static ElfW_Rel *qrel; /* ptr to next reloc entry reused */
85 void relocate_init(Section *sr)
87 qrel = (ElfW_Rel *) sr->data;
90 void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val)
92 int sym_index, esym_index;
94 sym_index = ELFW(R_SYM)(rel->r_info);
96 switch (type) {
97 case R_X86_64_64:
98 if (s1->output_type == TCC_OUTPUT_DLL) {
99 esym_index = s1->symtab_to_dynsym[sym_index];
100 qrel->r_offset = rel->r_offset;
101 if (esym_index) {
102 qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64);
103 qrel->r_addend = rel->r_addend;
104 qrel++;
105 break;
106 } else {
107 qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
108 qrel->r_addend = read64le(ptr) + val;
109 qrel++;
112 add64le(ptr, val);
113 break;
114 case R_X86_64_32:
115 case R_X86_64_32S:
116 if (s1->output_type == TCC_OUTPUT_DLL) {
117 /* XXX: this logic may depend on TCC's codegen
118 now TCC uses R_X86_64_32 even for a 64bit pointer */
119 qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
120 /* Use sign extension! */
121 qrel->r_addend = (int)read32le(ptr) + val;
122 qrel++;
124 add32le(ptr, val);
125 break;
127 case R_X86_64_PC32:
128 if (s1->output_type == TCC_OUTPUT_DLL) {
129 /* DLL relocation */
130 esym_index = s1->symtab_to_dynsym[sym_index];
131 if (esym_index) {
132 qrel->r_offset = rel->r_offset;
133 qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
134 /* Use sign extension! */
135 qrel->r_addend = (int)read32le(ptr) + rel->r_addend;
136 qrel++;
137 break;
140 goto plt32pc32;
142 case R_X86_64_PLT32:
143 /* fallthrough: val already holds the PLT slot address */
145 plt32pc32:
147 long long diff;
148 diff = (long long)val - addr;
149 if (diff < -2147483648LL || diff > 2147483647LL) {
150 tcc_error("internal error: relocation failed");
152 add32le(ptr, diff);
154 break;
155 case R_X86_64_GLOB_DAT:
156 case R_X86_64_JUMP_SLOT:
157 /* They don't need addend */
158 write64le(ptr, val - rel->r_addend);
159 break;
160 case R_X86_64_GOTPCREL:
161 case R_X86_64_GOTPCRELX:
162 case R_X86_64_REX_GOTPCRELX:
163 add32le(ptr, s1->got->sh_addr - addr +
164 s1->sym_attrs[sym_index].got_offset - 4);
165 break;
166 case R_X86_64_GOTTPOFF:
167 add32le(ptr, val - s1->got->sh_addr);
168 break;
169 case R_X86_64_GOT32:
170 /* we load the got offset */
171 add32le(ptr, s1->sym_attrs[sym_index].got_offset);
172 break;
176 #endif /* !TARGET_DEFS_ONLY */