Rev 647 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 647 | Rev 6429 | ||
---|---|---|---|
Line 16... | Line 16... | ||
16 | * You should have received a copy of the GNU Lesser General Public |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
19 | */ |
Line -... | Line 20... | ||
- | 20 | ||
- | 21 | #include "tcc.h" |
|
- | 22 | ||
- | 23 | /* Define this to get some debug output during relocation processing. */ |
|
- | 24 | #undef DEBUG_RELOC |
|
- | 25 | ||
- | 26 | /* XXX: avoid static variable */ |
|
- | 27 | static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ |
|
20 | 28 | ||
21 | static int put_elf_str(Section *s, const char *sym) |
29 | ST_FUNC int put_elf_str(Section *s, const char *sym) |
22 | { |
30 | { |
23 | int offset, len; |
31 | int offset, len; |
Line 24... | Line 32... | ||
24 | char *ptr; |
32 | char *ptr; |
Line 47... | Line 55... | ||
47 | 55 | ||
48 | /* rebuild hash table of section s */ |
56 | /* rebuild hash table of section s */ |
49 | /* NOTE: we do factorize the hash table code to go faster */ |
57 | /* NOTE: we do factorize the hash table code to go faster */ |
50 | static void rebuild_hash(Section *s, unsigned int nb_buckets) |
58 | static void rebuild_hash(Section *s, unsigned int nb_buckets) |
51 | { |
59 | { |
52 | Elf32_Sym *sym; |
60 | ElfW(Sym) *sym; |
53 | int *ptr, *hash, nb_syms, sym_index, h; |
61 | int *ptr, *hash, nb_syms, sym_index, h; |
Line 54... | Line 62... | ||
54 | char *strtab; |
62 | unsigned char *strtab; |
55 | 63 | ||
Line 56... | Line 64... | ||
56 | strtab = s->link->data; |
64 | strtab = s->link->data; |
57 | nb_syms = s->data_offset / sizeof(Elf32_Sym); |
65 | nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
58 | 66 | ||
59 | s->hash->data_offset = 0; |
67 | s->hash->data_offset = 0; |
60 | ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); |
68 | ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); |
61 | ptr[0] = nb_buckets; |
69 | ptr[0] = nb_buckets; |
62 | ptr[1] = nb_syms; |
70 | ptr[1] = nb_syms; |
63 | ptr += 2; |
71 | ptr += 2; |
Line 64... | Line 72... | ||
64 | hash = ptr; |
72 | hash = ptr; |
65 | memset(hash, 0, (nb_buckets + 1) * sizeof(int)); |
73 | memset(hash, 0, (nb_buckets + 1) * sizeof(int)); |
66 | ptr += nb_buckets + 1; |
74 | ptr += nb_buckets + 1; |
67 | 75 | ||
68 | sym = (Elf32_Sym *)s->data + 1; |
76 | sym = (ElfW(Sym) *)s->data + 1; |
69 | for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
77 | for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
70 | if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
78 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
71 | h = elf_hash(strtab + sym->st_name) % nb_buckets; |
79 | h = elf_hash(strtab + sym->st_name) % nb_buckets; |
Line 78... | Line 86... | ||
78 | sym++; |
86 | sym++; |
79 | } |
87 | } |
80 | } |
88 | } |
Line 81... | Line 89... | ||
81 | 89 | ||
82 | /* return the symbol number */ |
- | |
83 | static int put_elf_sym(Section *s, |
90 | /* return the symbol number */ |
84 | unsigned long value, unsigned long size, |
91 | ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, |
85 | int info, int other, int shndx, const char *name) |
92 | int info, int other, int shndx, const char *name) |
86 | { |
93 | { |
87 | int name_offset, sym_index; |
94 | int name_offset, sym_index; |
88 | int nbuckets, h; |
95 | int nbuckets, h; |
89 | Elf32_Sym *sym; |
96 | ElfW(Sym) *sym; |
Line 90... | Line 97... | ||
90 | Section *hs; |
97 | Section *hs; |
91 | 98 | ||
92 | sym = section_ptr_add(s, sizeof(Elf32_Sym)); |
99 | sym = section_ptr_add(s, sizeof(ElfW(Sym))); |
93 | if (name) |
100 | if (name) |
94 | name_offset = put_elf_str(s->link, name); |
101 | name_offset = put_elf_str(s->link, name); |
95 | else |
102 | else |
Line 99... | Line 106... | ||
99 | sym->st_value = value; |
106 | sym->st_value = value; |
100 | sym->st_size = size; |
107 | sym->st_size = size; |
101 | sym->st_info = info; |
108 | sym->st_info = info; |
102 | sym->st_other = other; |
109 | sym->st_other = other; |
103 | sym->st_shndx = shndx; |
110 | sym->st_shndx = shndx; |
104 | sym_index = sym - (Elf32_Sym *)s->data; |
111 | sym_index = sym - (ElfW(Sym) *)s->data; |
105 | hs = s->hash; |
112 | hs = s->hash; |
106 | if (hs) { |
113 | if (hs) { |
107 | int *ptr, *base; |
114 | int *ptr, *base; |
108 | ptr = section_ptr_add(hs, sizeof(int)); |
115 | ptr = section_ptr_add(hs, sizeof(int)); |
109 | base = (int *)hs->data; |
116 | base = (int *)hs->data; |
110 | /* only add global or weak symbols */ |
117 | /* only add global or weak symbols */ |
111 | if (ELF32_ST_BIND(info) != STB_LOCAL) { |
118 | if (ELFW(ST_BIND)(info) != STB_LOCAL) { |
112 | /* add another hashing entry */ |
119 | /* add another hashing entry */ |
113 | nbuckets = base[0]; |
120 | nbuckets = base[0]; |
114 | h = elf_hash(name) % nbuckets; |
121 | h = elf_hash((unsigned char *) name) % nbuckets; |
115 | *ptr = base[2 + h]; |
122 | *ptr = base[2 + h]; |
116 | base[2 + h] = sym_index; |
123 | base[2 + h] = sym_index; |
117 | base[1]++; |
124 | base[1]++; |
118 | /* we resize the hash table */ |
125 | /* we resize the hash table */ |
119 | hs->nb_hashed_syms++; |
126 | hs->nb_hashed_syms++; |
Line 128... | Line 135... | ||
128 | return sym_index; |
135 | return sym_index; |
129 | } |
136 | } |
Line 130... | Line 137... | ||
130 | 137 | ||
131 | /* find global ELF symbol 'name' and return its index. Return 0 if not |
138 | /* find global ELF symbol 'name' and return its index. Return 0 if not |
132 | found. */ |
139 | found. */ |
133 | static int find_elf_sym(Section *s, const char *name) |
140 | ST_FUNC int find_elf_sym(Section *s, const char *name) |
134 | { |
141 | { |
135 | Elf32_Sym *sym; |
142 | ElfW(Sym) *sym; |
136 | Section *hs; |
143 | Section *hs; |
137 | int nbuckets, sym_index, h; |
144 | int nbuckets, sym_index, h; |
Line 138... | Line 145... | ||
138 | const char *name1; |
145 | const char *name1; |
139 | 146 | ||
140 | hs = s->hash; |
147 | hs = s->hash; |
141 | if (!hs) |
148 | if (!hs) |
142 | return 0; |
149 | return 0; |
143 | nbuckets = ((int *)hs->data)[0]; |
150 | nbuckets = ((int *)hs->data)[0]; |
144 | h = elf_hash(name) % nbuckets; |
151 | h = elf_hash((unsigned char *) name) % nbuckets; |
145 | sym_index = ((int *)hs->data)[2 + h]; |
152 | sym_index = ((int *)hs->data)[2 + h]; |
146 | while (sym_index != 0) { |
153 | while (sym_index != 0) { |
147 | sym = &((Elf32_Sym *)s->data)[sym_index]; |
154 | sym = &((ElfW(Sym) *)s->data)[sym_index]; |
148 | name1 = s->link->data + sym->st_name; |
155 | name1 = (char *) s->link->data + sym->st_name; |
149 | if (!strcmp(name, name1)) |
156 | if (!strcmp(name, name1)) |
150 | return sym_index; |
157 | return sym_index; |
151 | sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; |
158 | sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; |
152 | } |
159 | } |
Line 153... | Line 160... | ||
153 | return 0; |
160 | return 0; |
154 | } |
161 | } |
155 | 162 | ||
156 | /* return elf symbol value or error */ |
163 | /* return elf symbol value, signal error if 'err' is nonzero */ |
157 | int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name) |
164 | ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err) |
Line 158... | Line 165... | ||
158 | { |
165 | { |
- | 166 | int sym_index; |
|
159 | int sym_index; |
167 | ElfW(Sym) *sym; |
160 | Elf32_Sym *sym; |
168 | |
161 | 169 | sym_index = find_elf_sym(s->symtab, name); |
|
162 | sym_index = find_elf_sym(symtab_section, name); |
- | |
163 | if (!sym_index) |
170 | sym = &((ElfW(Sym) *)s->symtab->data)[sym_index]; |
164 | return -1; |
171 | if (!sym_index || sym->st_shndx == SHN_UNDEF) { |
- | 172 | if (err) |
|
- | 173 | tcc_error("%s not defined", name); |
|
- | 174 | return 0; |
|
- | 175 | } |
|
- | 176 | return sym->st_value; |
|
- | 177 | } |
|
- | 178 | ||
- | 179 | /* return elf symbol value */ |
|
Line -... | Line 180... | ||
- | 180 | LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) |
|
- | 181 | { |
|
165 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
182 | return (void*)(uintptr_t)get_elf_sym_addr(s, name, 0); |
166 | *pval = sym->st_value; |
183 | } |
167 | return 0; |
- | |
168 | } |
184 | |
169 | - | ||
170 | void *tcc_get_symbol_err(TCCState *s, const char *name) |
- | |
171 | { |
185 | #if defined TCC_IS_NATIVE || defined TCC_TARGET_PE || defined TCC_TARGET_MEOS |
- | 186 | /* return elf symbol value or error */ |
|
Line 172... | Line 187... | ||
172 | unsigned long val; |
187 | ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) |
173 | if (tcc_get_symbol(s, &val, name) < 0) |
188 | { |
174 | error("%s not defined", name); |
189 | return (void*)(uintptr_t)get_elf_sym_addr(s, name, 1); |
175 | return (void *)val; |
190 | } |
176 | } |
191 | #endif |
177 | 192 | ||
178 | /* add an elf symbol : check if it is already defined and patch |
193 | /* add an elf symbol : check if it is already defined and patch |
- | 194 | it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ |
|
Line 179... | Line 195... | ||
179 | it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ |
195 | ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size, |
180 | static int add_elf_sym(Section *s, unsigned long value, unsigned long size, |
196 | int info, int other, int sh_num, const char *name) |
- | 197 | { |
|
Line 181... | Line 198... | ||
181 | int info, int other, int sh_num, const char *name) |
198 | ElfW(Sym) *esym; |
182 | { |
199 | int sym_bind, sym_index, sym_type, esym_bind; |
183 | Elf32_Sym *esym; |
200 | unsigned char sym_vis, esym_vis, new_vis; |
184 | int sym_bind, sym_index, sym_type, esym_bind; |
201 | |
185 | 202 | sym_bind = ELFW(ST_BIND)(info); |
|
186 | sym_bind = ELF32_ST_BIND(info); |
203 | sym_type = ELFW(ST_TYPE)(info); |
187 | sym_type = ELF32_ST_TYPE(info); |
204 | sym_vis = ELFW(ST_VISIBILITY)(other); |
188 | 205 | ||
- | 206 | if (sym_bind != STB_LOCAL) { |
|
- | 207 | /* we search global or weak symbols */ |
|
- | 208 | sym_index = find_elf_sym(s, name); |
|
- | 209 | if (!sym_index) |
|
- | 210 | goto do_def; |
|
- | 211 | esym = &((ElfW(Sym) *)s->data)[sym_index]; |
|
- | 212 | if (esym->st_shndx != SHN_UNDEF) { |
|
- | 213 | esym_bind = ELFW(ST_BIND)(esym->st_info); |
|
- | 214 | /* propagate the most constraining visibility */ |
|
- | 215 | /* STV_DEFAULT(0) |
|
- | 216 | esym_vis = ELFW(ST_VISIBILITY)(esym->st_other); |
|
- | 217 | if (esym_vis == STV_DEFAULT) { |
|
- | 218 | new_vis = sym_vis; |
|
189 | if (sym_bind != STB_LOCAL) { |
219 | } else if (sym_vis == STV_DEFAULT) { |
190 | /* we search global or weak symbols */ |
220 | new_vis = esym_vis; |
191 | sym_index = find_elf_sym(s, name); |
221 | } else { |
192 | if (!sym_index) |
222 | new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; |
193 | goto do_def; |
223 | } |
194 | esym = &((Elf32_Sym *)s->data)[sym_index]; |
224 | esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
195 | if (esym->st_shndx != SHN_UNDEF) { |
225 | | new_vis; |
196 | esym_bind = ELF32_ST_BIND(esym->st_info); |
226 | other = esym->st_other; /* in case we have to patch esym */ |
- | 227 | if (sh_num == SHN_UNDEF) { |
|
- | 228 | /* ignore adding of undefined symbol if the |
|
- | 229 | corresponding symbol is already defined */ |
|
- | 230 | } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { |
|
- | 231 | /* global overrides weak, so patch */ |
|
- | 232 | goto do_patch; |
|
- | 233 | } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { |
|
- | 234 | /* weak is ignored if already global */ |
|
- | 235 | } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { |
|
- | 236 | /* keep first-found weak definition, ignore subsequents */ |
|
- | 237 | } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { |
|
197 | if (sh_num == SHN_UNDEF) { |
238 | /* ignore hidden symbols after */ |
198 | /* ignore adding of undefined symbol if the |
239 | } else if (esym->st_shndx == SHN_COMMON |
199 | corresponding symbol is already defined */ |
240 | && (sh_num < SHN_LORESERVE || sh_num == SHN_COMMON)) { |
200 | } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { |
241 | /* gr: Happens with 'tcc ... -static tcctest.c' on e.g. Ubuntu 6.01 |
201 | /* global overrides weak, so patch */ |
242 | No idea if this is the correct solution ... */ |
202 | goto do_patch; |
- | |
203 | } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { |
- | |
204 | /* weak is ignored if already global */ |
243 | goto do_patch; |
205 | } else { |
244 | } else if (s == tcc_state->dynsymtab_section) { |
206 | #if 0 |
245 | /* we accept that two DLL define the same symbol */ |
207 | printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n", |
246 | } else { |
208 | sym_bind, sh_num, esym_bind, esym->st_shndx); |
247 | #if 0 |
209 | #endif |
248 | printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", |
- | 249 | sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis); |
|
210 | /* NOTE: we accept that two DLL define the same symbol */ |
250 | #endif |
211 | if (s != tcc_state->dynsymtab_section) |
251 | tcc_error_noabort("'%s' defined twice... may be -fcommon is needed?", name); |
212 | error_noabort("'%s' defined twice", name); |
252 | } |
213 | } |
253 | } else { |
214 | } else { |
254 | do_patch: |
215 | do_patch: |
255 | esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); |
216 | esym->st_info = ELF32_ST_INFO(sym_bind, sym_type); |
256 | esym->st_shndx = sh_num; |
217 | esym->st_shndx = sh_num; |
257 | new_undef_sym = 1; |
218 | esym->st_value = value; |
258 | esym->st_value = value; |
219 | esym->st_size = size; |
259 | esym->st_size = size; |
220 | esym->st_other = other; |
260 | esym->st_other = other; |
221 | } |
261 | } |
Line 222... | Line 262... | ||
222 | } else { |
262 | } else { |
223 | do_def: |
263 | do_def: |
224 | sym_index = put_elf_sym(s, value, size, |
264 | sym_index = put_elf_sym(s, value, size, |
225 | ELF32_ST_INFO(sym_bind, sym_type), other, |
265 | ELFW(ST_INFO)(sym_bind, sym_type), other, |
226 | sh_num, name); |
266 | sh_num, name); |
227 | } |
267 | } |
228 | return sym_index; |
268 | return sym_index; |
Line 229... | Line 269... | ||
229 | } |
269 | } |
230 | 270 | ||
231 | /* put relocation */ |
271 | /* put relocation */ |
232 | static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
272 | ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, |
233 | int type, int symbol) |
273 | int type, int symbol, addr_t addend) |
234 | { |
274 | { |
235 | char buf[256]; |
275 | char buf[256]; |
236 | Section *sr; |
276 | Section *sr; |
237 | Elf32_Rel *rel; |
277 | ElfW_Rel *rel; |
238 | 278 | ||
239 | sr = s->reloc; |
279 | sr = s->reloc; |
240 | if (!sr) { |
280 | if (!sr) { |
241 | /* if no relocation section, create it */ |
281 | /* if no relocation section, create it */ |
242 | snprintf(buf, sizeof(buf), ".rel%s", s->name); |
282 | snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); |
243 | /* if the symtab is allocated, then we consider the relocation |
283 | /* if the symtab is allocated, then we consider the relocation |
- | 284 | are also */ |
|
- | 285 | sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags); |
|
- | 286 | sr->sh_entsize = sizeof(ElfW_Rel); |
|
- | 287 | sr->link = symtab; |
|
- | 288 | sr->sh_info = s->sh_num; |
|
- | 289 | s->reloc = sr; |
|
244 | are also */ |
290 | } |
Line -... | Line 291... | ||
- | 291 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
|
- | 292 | rel->r_offset = offset; |
|
- | 293 | rel->r_info = ELFW(R_INFO)(symbol, type); |
|
245 | sr = new_section(tcc_state, buf, SHT_REL, symtab->sh_flags); |
294 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
- | 295 | rel->r_addend = addend; |
|
Line 246... | Line -... | ||
246 | sr->sh_entsize = sizeof(Elf32_Rel); |
- | |
247 | sr->link = symtab; |
- | |
248 | sr->sh_info = s->sh_num; |
- | |
249 | s->reloc = sr; |
- | |
250 | } |
296 | #else |
251 | rel = section_ptr_add(sr, sizeof(Elf32_Rel)); |
- | |
252 | rel->r_offset = offset; |
- | |
Line 253... | Line 297... | ||
253 | rel->r_info = ELF32_R_INFO(symbol, type); |
297 | if (addend) |
254 | } |
298 | tcc_error("non-zero addend on REL architecture"); |
255 | 299 | #endif |
|
256 | /* put stab debug information */ |
300 | } |
Line 257... | Line 301... | ||
257 | 301 | ||
Line 278... | Line 322... | ||
278 | sym->n_other = other; |
322 | sym->n_other = other; |
279 | sym->n_desc = desc; |
323 | sym->n_desc = desc; |
280 | sym->n_value = value; |
324 | sym->n_value = value; |
281 | } |
325 | } |
Line 282... | Line 326... | ||
282 | 326 | ||
283 | static void put_stabs_r(const char *str, int type, int other, int desc, |
327 | ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, |
284 | unsigned long value, Section *sec, int sym_index) |
328 | unsigned long value, Section *sec, int sym_index) |
285 | { |
329 | { |
286 | put_stabs(str, type, other, desc, value); |
330 | put_stabs(str, type, other, desc, value); |
287 | put_elf_reloc(symtab_section, stab_section, |
331 | put_elf_reloc(symtab_section, stab_section, |
288 | stab_section->data_offset - sizeof(unsigned long), |
332 | stab_section->data_offset - sizeof(unsigned int), |
289 | R_DATA_32, sym_index); |
333 | R_DATA_32, sym_index); |
Line 290... | Line 334... | ||
290 | } |
334 | } |
291 | 335 | ||
292 | static void put_stabn(int type, int other, int desc, int value) |
336 | ST_FUNC void put_stabn(int type, int other, int desc, int value) |
293 | { |
337 | { |
Line 294... | Line 338... | ||
294 | put_stabs(NULL, type, other, desc, value); |
338 | put_stabs(NULL, type, other, desc, value); |
295 | } |
339 | } |
296 | 340 | ||
297 | static void put_stabd(int type, int other, int desc) |
341 | ST_FUNC void put_stabd(int type, int other, int desc) |
Line -... | Line 342... | ||
- | 342 | { |
|
- | 343 | put_stabs(NULL, type, other, desc, 0); |
|
- | 344 | } |
|
- | 345 | ||
- | 346 | /* Browse each elem of type |
|
- | 347 | using variable |
|
298 | { |
348 | #define for_each_elem(sec, startoff, elem, type) \ |
299 | put_stabs(NULL, type, other, desc, 0); |
349 | for (elem = (type *) sec->data + startoff; \ |
300 | } |
350 | elem < (type *) (sec->data + sec->data_offset); elem++) |
301 | 351 | ||
302 | /* In an ELF file symbol table, the local symbols must appear below |
352 | /* In an ELF file symbol table, the local symbols must appear below |
303 | the global and weak ones. Since TCC cannot sort it while generating |
353 | the global and weak ones. Since TCC cannot sort it while generating |
304 | the code, we must do it after. All the relocation tables are also |
354 | the code, we must do it after. All the relocation tables are also |
305 | modified to take into account the symbol table sorting */ |
355 | modified to take into account the symbol table sorting */ |
306 | static void sort_syms(TCCState *s1, Section *s) |
356 | static void sort_syms(TCCState *s1, Section *s) |
307 | { |
357 | { |
308 | int *old_to_new_syms; |
358 | int *old_to_new_syms; |
309 | Elf32_Sym *new_syms; |
359 | ElfW(Sym) *new_syms; |
310 | int nb_syms, i; |
360 | int nb_syms, i; |
Line 311... | Line 361... | ||
311 | Elf32_Sym *p, *q; |
361 | ElfW(Sym) *p, *q; |
312 | Elf32_Rel *rel, *rel_end; |
362 | ElfW_Rel *rel; |
313 | Section *sr; |
363 | Section *sr; |
Line 314... | Line 364... | ||
314 | int type, sym_index; |
364 | int type, sym_index; |
315 | 365 | ||
316 | nb_syms = s->data_offset / sizeof(Elf32_Sym); |
366 | nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
317 | new_syms = tcc_malloc(nb_syms * sizeof(Elf32_Sym)); |
367 | new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); |
318 | old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); |
368 | old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); |
319 | 369 | ||
320 | /* first pass for local symbols */ |
370 | /* first pass for local symbols */ |
321 | p = (Elf32_Sym *)s->data; |
371 | p = (ElfW(Sym) *)s->data; |
322 | q = new_syms; |
372 | q = new_syms; |
323 | for(i = 0; i < nb_syms; i++) { |
373 | for(i = 0; i < nb_syms; i++) { |
324 | if (ELF32_ST_BIND(p->st_info) == STB_LOCAL) { |
374 | if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { |
325 | old_to_new_syms[i] = q - new_syms; |
375 | old_to_new_syms[i] = q - new_syms; |
Line 326... | Line 376... | ||
326 | *q++ = *p; |
376 | *q++ = *p; |
327 | } |
377 | } |
328 | p++; |
378 | p++; |
329 | } |
379 | } |
330 | /* save the number of local symbols in section header */ |
380 | /* save the number of local symbols in section header */ |
331 | s->sh_info = q - new_syms; |
381 | s->sh_info = q - new_syms; |
332 | 382 | ||
333 | /* then second pass for non local symbols */ |
383 | /* then second pass for non local symbols */ |
334 | p = (Elf32_Sym *)s->data; |
384 | p = (ElfW(Sym) *)s->data; |
Line 335... | Line 385... | ||
335 | for(i = 0; i < nb_syms; i++) { |
385 | for(i = 0; i < nb_syms; i++) { |
336 | if (ELF32_ST_BIND(p->st_info) != STB_LOCAL) { |
386 | if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { |
337 | old_to_new_syms[i] = q - new_syms; |
387 | old_to_new_syms[i] = q - new_syms; |
Line 338... | Line 388... | ||
338 | *q++ = *p; |
388 | *q++ = *p; |
339 | } |
389 | } |
340 | p++; |
390 | p++; |
341 | } |
391 | } |
342 | - | ||
343 | /* we copy the new symbols to the old */ |
392 | |
344 | memcpy(s->data, new_syms, nb_syms * sizeof(Elf32_Sym)); |
- | |
345 | tcc_free(new_syms); |
- | |
346 | 393 | /* we copy the new symbols to the old */ |
|
347 | /* now we modify all the relocations */ |
394 | memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); |
348 | for(i = 1; i < s1->nb_sections; i++) { |
395 | tcc_free(new_syms); |
349 | sr = s1->sections[i]; |
396 | |
350 | if (sr->sh_type == SHT_REL && sr->link == s) { |
397 | /* now we modify all the relocations */ |
351 | rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
398 | for(i = 1; i < s1->nb_sections; i++) { |
352 | for(rel = (Elf32_Rel *)sr->data; |
399 | sr = s1->sections[i]; |
Line 353... | Line 400... | ||
353 | rel < rel_end; |
400 | if (sr->sh_type == SHT_RELX && sr->link == s) { |
354 | rel++) { |
401 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
Line 355... | Line 402... | ||
355 | sym_index = ELF32_R_SYM(rel->r_info); |
402 | sym_index = ELFW(R_SYM)(rel->r_info); |
356 | type = ELF32_R_TYPE(rel->r_info); |
403 | type = ELFW(R_TYPE)(rel->r_info); |
357 | sym_index = old_to_new_syms[sym_index]; |
404 | sym_index = old_to_new_syms[sym_index]; |
358 | rel->r_info = ELF32_R_INFO(sym_index, type); |
405 | rel->r_info = ELFW(R_INFO)(sym_index, type); |
359 | } |
406 | } |
Line 360... | Line -... | ||
360 | } |
- | |
361 | } |
407 | } |
362 | - | ||
363 | tcc_free(old_to_new_syms); |
- | |
364 | } |
408 | } |
365 | 409 | ||
366 | /* relocate common symbols in the .bss section */ |
410 | tcc_free(old_to_new_syms); |
367 | static void relocate_common_syms(void) |
411 | } |
368 | { |
412 | |
Line 386... | Line 430... | ||
386 | } |
430 | } |
387 | } |
431 | } |
Line 388... | Line 432... | ||
388 | 432 | ||
389 | /* relocate symbol table, resolve undefined symbols if do_resolve is |
433 | /* relocate symbol table, resolve undefined symbols if do_resolve is |
390 | true and output error if undefined symbol. */ |
434 | true and output error if undefined symbol. */ |
391 | static void relocate_syms(TCCState *s1, int do_resolve) |
435 | ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) |
392 | { |
436 | { |
393 | Elf32_Sym *sym, *esym, *sym_end; |
437 | ElfW(Sym) *sym, *esym; |
394 | int sym_bind, sh_num, sym_index; |
438 | int sym_bind, sh_num, sym_index; |
395 | const char *name; |
- | |
Line 396... | Line -... | ||
396 | unsigned long addr; |
- | |
397 | 439 | const char *name; |
|
398 | sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); |
- | |
399 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
- | |
400 | sym < sym_end; |
440 | |
401 | sym++) { |
441 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
402 | sh_num = sym->st_shndx; |
442 | sh_num = sym->st_shndx; |
- | 443 | if (sh_num == SHN_UNDEF) { |
|
403 | if (sh_num == SHN_UNDEF) { |
444 | name = (char *) strtab_section->data + sym->st_name; |
- | 445 | /* Use ld.so to resolve symbol for us (for tcc -run) */ |
|
- | 446 | if (do_resolve) { |
|
404 | name = strtab_section->data + sym->st_name; |
447 | #if defined TCC_IS_NATIVE && !defined _WIN32 |
405 | if (do_resolve) { |
448 | void *addr; |
406 | name = symtab_section->link->data + sym->st_name; |
449 | name = (char *) symtab_section->link->data + sym->st_name; |
407 | addr = (unsigned long)resolve_sym(s1, name, ELF32_ST_TYPE(sym->st_info)); |
450 | addr = resolve_sym(s1, name); |
- | 451 | if (addr) { |
|
- | 452 | sym->st_value = (addr_t)addr; |
|
- | 453 | #ifdef DEBUG_RELOC |
|
408 | if (addr) { |
454 | printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value); |
409 | sym->st_value = addr; |
455 | #endif |
- | 456 | goto found; |
|
410 | goto found; |
457 | } |
411 | } |
458 | #endif |
412 | } else if (s1->dynsym) { |
459 | } else if (s1->dynsym) { |
413 | /* if dynamic symbol exist, then use it */ |
460 | /* if dynamic symbol exist, then use it */ |
414 | sym_index = find_elf_sym(s1->dynsym, name); |
461 | sym_index = find_elf_sym(s1->dynsym, name); |
415 | if (sym_index) { |
462 | if (sym_index) { |
416 | esym = &((Elf32_Sym *)s1->dynsym->data)[sym_index]; |
463 | esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index]; |
417 | sym->st_value = esym->st_value; |
464 | sym->st_value = esym->st_value; |
418 | goto found; |
465 | goto found; |
419 | } |
466 | } |
420 | } |
467 | } |
421 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
468 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
422 | it */ |
469 | it */ |
423 | if (!strcmp(name, "_fp_hw")) |
470 | if (!strcmp(name, "_fp_hw")) |
424 | goto found; |
471 | goto found; |
425 | /* only weak symbols are accepted to be undefined. Their |
472 | /* only weak symbols are accepted to be undefined. Their |
426 | value is zero */ |
473 | value is zero */ |
427 | sym_bind = ELF32_ST_BIND(sym->st_info); |
474 | sym_bind = ELFW(ST_BIND)(sym->st_info); |
428 | if (sym_bind == STB_WEAK) { |
475 | if (sym_bind == STB_WEAK) { |
429 | sym->st_value = 0; |
476 | sym->st_value = 0; |
430 | } else { |
477 | } else { |
431 | error_noabort("undefined symbol '%s'", name); |
478 | tcc_error_noabort("undefined symbol '%s'", name); |
432 | } |
479 | } |
433 | } else if (sh_num < SHN_LORESERVE) { |
480 | } else if (sh_num < SHN_LORESERVE) { |
434 | /* add section base */ |
481 | /* add section base */ |
435 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
482 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
436 | } |
483 | } |
437 | found: ; |
484 | found: ; |
Line 438... | Line 485... | ||
438 | } |
485 | } |
- | 486 | } |
|
439 | } |
487 | |
440 | 488 | /* relocate a given section (CPU dependent) by applying the relocations |
|
441 | /* relocate a given section (CPU dependent) */ |
489 | in the associated relocation section */ |
442 | static void relocate_section(TCCState *s1, Section *s) |
490 | ST_FUNC void relocate_section(TCCState *s1, Section *s) |
443 | { |
491 | { |
444 | Section *sr; |
492 | Section *sr = s->reloc; |
445 | Elf32_Rel *rel, *rel_end, *qrel; |
493 | ElfW_Rel *rel; |
446 | Elf32_Sym *sym; |
494 | ElfW(Sym) *sym; |
447 | int type, sym_index; |
495 | int type, sym_index; |
- | 496 | unsigned char *ptr; |
|
448 | unsigned char *ptr; |
497 | addr_t val, addr; |
449 | unsigned long val, addr; |
498 | #if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
Line 450... | Line -... | ||
450 | #if defined(TCC_TARGET_I386) |
- | |
451 | int esym_index; |
- | |
452 | #endif |
499 | ElfW_Rel *qrel = (ElfW_Rel *) sr->data; /* ptr to next reloc entry reused */ |
453 | - | ||
454 | sr = s->reloc; |
- | |
455 | rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
- | |
456 | qrel = (Elf32_Rel *)sr->data; |
500 | int esym_index; |
Line 457... | Line 501... | ||
457 | for(rel = qrel; |
501 | #endif |
458 | rel < rel_end; |
502 | |
459 | rel++) { |
503 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
- | 504 | ptr = s->data + rel->r_offset; |
|
- | 505 | ||
- | 506 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
460 | ptr = s->data + rel->r_offset; |
507 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
461 | 508 | val = sym->st_value; |
|
Line 462... | Line 509... | ||
462 | sym_index = ELF32_R_SYM(rel->r_info); |
509 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
463 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
510 | val += rel->r_addend; |
464 | val = sym->st_value; |
511 | #endif |
465 | type = ELF32_R_TYPE(rel->r_info); |
512 | type = ELFW(R_TYPE)(rel->r_info); |
466 | addr = s->sh_addr + rel->r_offset; |
513 | addr = s->sh_addr + rel->r_offset; |
467 | 514 | ||
468 | /* CPU specific */ |
515 | /* CPU specific */ |
469 | switch(type) { |
516 | switch(type) { |
470 | #if defined(TCC_TARGET_I386) |
517 | #if defined(TCC_TARGET_I386) |
471 | case R_386_32: |
518 | case R_386_32: |
472 | if (s1->output_type == TCC_OUTPUT_DLL) { |
519 | if (s1->output_type == TCC_OUTPUT_DLL) { |
473 | esym_index = s1->symtab_to_dynsym[sym_index]; |
520 | esym_index = s1->symtab_to_dynsym[sym_index]; |
474 | qrel->r_offset = rel->r_offset; |
521 | qrel->r_offset = rel->r_offset; |
475 | if (esym_index) { |
522 | if (esym_index) { |
476 | qrel->r_info = ELF32_R_INFO(esym_index, R_386_32); |
523 | qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); |
477 | qrel++; |
524 | qrel++; |
478 | break; |
525 | break; |
479 | } else { |
526 | } else { |
480 | qrel->r_info = ELF32_R_INFO(0, R_386_RELATIVE); |
527 | qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); |
481 | qrel++; |
528 | qrel++; |
482 | } |
529 | } |
483 | } |
530 | } |
484 | *(int *)ptr += val; |
531 | write32le(ptr, read32le(ptr) + val); |
485 | break; |
532 | break; |
486 | case R_386_PC32: |
533 | case R_386_PC32: |
487 | if (s1->output_type == TCC_OUTPUT_DLL) { |
534 | if (s1->output_type == TCC_OUTPUT_DLL) { |
488 | /* DLL relocation */ |
535 | /* DLL relocation */ |
489 | esym_index = s1->symtab_to_dynsym[sym_index]; |
536 | esym_index = s1->symtab_to_dynsym[sym_index]; |
490 | if (esym_index) { |
537 | if (esym_index) { |
491 | qrel->r_offset = rel->r_offset; |
538 | qrel->r_offset = rel->r_offset; |
492 | qrel->r_info = ELF32_R_INFO(esym_index, R_386_PC32); |
539 | qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); |
493 | qrel++; |
540 | qrel++; |
494 | break; |
541 | break; |
495 | } |
542 | } |
496 | } |
543 | } |
497 | *(int *)ptr += val - addr; |
544 | write32le(ptr, read32le(ptr) + val - addr); |
498 | break; |
545 | break; |
499 | case R_386_PLT32: |
546 | case R_386_PLT32: |
500 | *(int *)ptr += val - addr; |
547 | write32le(ptr, read32le(ptr) + val - addr); |
501 | break; |
548 | break; |
502 | case R_386_GLOB_DAT: |
549 | case R_386_GLOB_DAT: |
503 | case R_386_JMP_SLOT: |
550 | case R_386_JMP_SLOT: |
504 | *(int *)ptr = val; |
551 | write32le(ptr, val); |
505 | break; |
552 | break; |
506 | case R_386_GOTPC: |
553 | case R_386_GOTPC: |
- | 554 | write32le(ptr, read32le(ptr) + s1->got->sh_addr - addr); |
|
507 | *(int *)ptr += s1->got->sh_addr - addr; |
555 | break; |
508 | break; |
556 | case R_386_GOTOFF: |
- | 557 | write32le(ptr, read32le(ptr) + val - s1->got->sh_addr); |
|
- | 558 | break; |
|
- | 559 | case R_386_GOT32: |
|
- | 560 | case R_386_GOT32X: |
|
- | 561 | /* we load the got offset */ |
|
- | 562 | write32le(ptr, read32le(ptr) + s1->sym_attrs[sym_index].got_offset); |
|
- | 563 | break; |
|
- | 564 | case R_386_16: |
|
- | 565 | if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { |
|
- | 566 | output_file: |
|
- | 567 | tcc_error("can only produce 16-bit binary files"); |
|
- | 568 | } |
|
- | 569 | write16le(ptr, read16le(ptr) + val); |
|
- | 570 | break; |
|
- | 571 | case R_386_PC16: |
|
- | 572 | if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) |
|
- | 573 | goto output_file; |
|
- | 574 | write16le(ptr, read16le(ptr) + val - addr); |
|
- | 575 | break; |
|
- | 576 | case R_386_RELATIVE: |
|
- | 577 | /* do nothing */ |
|
- | 578 | break; |
|
- | 579 | case R_386_COPY: |
|
- | 580 | /* This reloction must copy initialized data from the library |
|
- | 581 | to the program .bss segment. Currently made like for ARM |
|
509 | case R_386_GOTOFF: |
582 | (to remove noise of defaukt case). Is this true? |
510 | *(int *)ptr += val - s1->got->sh_addr; |
583 | */ |
511 | break; |
584 | break; |
- | 585 | default: |
|
- | 586 | fprintf(stderr,"FIXME: handle reloc type %d at %x [%p] to %x\n", |
|
512 | case R_386_GOT32: |
587 | type, (unsigned)addr, ptr, (unsigned)val); |
513 | /* we load the got offset */ |
588 | break; |
514 | *(int *)ptr += s1->got_offsets[sym_index]; |
589 | #elif defined(TCC_TARGET_ARM) |
515 | break; |
590 | case R_ARM_PC24: |
- | 591 | case R_ARM_CALL: |
|
- | 592 | case R_ARM_JUMP24: |
|
- | 593 | case R_ARM_PLT32: |
|
- | 594 | { |
|
- | 595 | int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; |
|
516 | #elif defined(TCC_TARGET_ARM) |
596 | x = (*(int *) ptr) & 0xffffff; |
517 | case R_ARM_PC24: |
597 | if (sym->st_shndx == SHN_UNDEF) |
518 | case R_ARM_PLT32: |
598 | val = s1->plt->sh_addr; |
519 | { |
599 | #ifdef DEBUG_RELOC |
- | 600 | printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); |
|
- | 601 | #endif |
|
- | 602 | (*(int *)ptr) &= 0xff000000; |
|
- | 603 | if (x & 0x800000) |
|
520 | int x; |
604 | x -= 0x1000000; |
- | 605 | x <<= 2; |
|
- | 606 | blx_avail = (TCC_ARM_VERSION >= 5); |
|
- | 607 | is_thumb = val & 1; |
|
- | 608 | is_bl = (*(unsigned *) ptr) >> 24 == 0xeb; |
|
- | 609 | is_call = (type == R_ARM_CALL || (type == R_ARM_PC24 && is_bl)); |
|
- | 610 | x += val - addr; |
|
521 | x = (*(int *)ptr)&0xffffff; |
611 | #ifdef DEBUG_RELOC |
522 | (*(int *)ptr) &= 0xff000000; |
612 | printf (" newx=0x%x name=%s\n", x, |
523 | if (x & 0x800000) |
613 | (char *) symtab_section->link->data + sym->st_name); |
524 | x -= 0x1000000; |
614 | #endif |
- | 615 | h = x & 2; |
|
- | 616 | th_ko = (x & 3) && (!blx_avail || !is_call); |
|
- | 617 | if (th_ko || x >= 0x2000000 || x < -0x2000000) |
|
- | 618 | tcc_error("can't relocate value at %x,%d",addr, type); |
|
- | 619 | x >>= 2; |
|
525 | x *= 4; |
620 | x &= 0xffffff; |
526 | x += val - addr; |
621 | /* Only reached if blx is avail and it is a call */ |
527 | if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) |
622 | if (is_thumb) { |
- | 623 | x |= h << 24; |
|
- | 624 | (*(int *)ptr) = 0xfa << 24; /* bl -> blx */ |
|
- | 625 | } |
|
- | 626 | (*(int *) ptr) |= x; |
|
- | 627 | } |
|
- | 628 | break; |
|
- | 629 | /* Since these relocations only concern Thumb-2 and blx instruction was |
|
- | 630 | introduced before Thumb-2, we can assume blx is available and not |
|
- | 631 | guard its use */ |
|
- | 632 | case R_ARM_THM_PC22: |
|
- | 633 | case R_ARM_THM_JUMP24: |
|
- | 634 | { |
|
- | 635 | int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; |
|
- | 636 | int to_thumb, is_call, to_plt, blx_bit = 1 << 12; |
|
- | 637 | Section *plt; |
|
- | 638 | ||
- | 639 | /* weak reference */ |
|
- | 640 | if (sym->st_shndx == SHN_UNDEF && |
|
- | 641 | ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
|
- | 642 | break; |
|
- | 643 | ||
- | 644 | /* Get initial offset */ |
|
- | 645 | hi = (*(uint16_t *)ptr); |
|
- | 646 | lo = (*(uint16_t *)(ptr+2)); |
|
- | 647 | s = (hi >> 10) & 1; |
|
- | 648 | j1 = (lo >> 13) & 1; |
|
- | 649 | j2 = (lo >> 11) & 1; |
|
- | 650 | i1 = (j1 ^ s) ^ 1; |
|
- | 651 | i2 = (j2 ^ s) ^ 1; |
|
- | 652 | imm10 = hi & 0x3ff; |
|
- | 653 | imm11 = lo & 0x7ff; |
|
- | 654 | x = (s << 24) | (i1 << 23) | (i2 << 22) | |
|
- | 655 | (imm10 << 12) | (imm11 << 1); |
|
- | 656 | if (x & 0x01000000) |
|
- | 657 | x -= 0x02000000; |
|
- | 658 | ||
- | 659 | /* Relocation infos */ |
|
- | 660 | to_thumb = val & 1; |
|
- | 661 | plt = s1->plt; |
|
- | 662 | to_plt = (val >= plt->sh_addr) && |
|
- | 663 | (val < plt->sh_addr + plt->data_offset); |
|
- | 664 | is_call = (type == R_ARM_THM_PC22); |
|
- | 665 | ||
- | 666 | /* Compute final offset */ |
|
- | 667 | if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ |
|
- | 668 | x -= 4; |
|
- | 669 | x += val - addr; |
|
- | 670 | if (!to_thumb && is_call) { |
|
- | 671 | blx_bit = 0; /* bl -> blx */ |
|
- | 672 | x = (x + 3) & -4; /* Compute offset from aligned PC */ |
|
- | 673 | } |
|
- | 674 | ||
- | 675 | /* Check that relocation is possible |
|
- | 676 | * offset must not be out of range |
|
- | 677 | * if target is to be entered in arm mode: |
|
- | 678 | - bit 1 must not set |
|
- | 679 | - instruction must be a call (bl) or a jump to PLT */ |
|
- | 680 | if (!to_thumb || x >= 0x1000000 || x < -0x1000000) |
|
- | 681 | if (to_thumb || (val & 2) || (!is_call && !to_plt)) |
|
- | 682 | tcc_error("can't relocate value at %x,%d",addr, type); |
|
- | 683 | ||
- | 684 | /* Compute and store final offset */ |
|
- | 685 | s = (x >> 24) & 1; |
|
- | 686 | i1 = (x >> 23) & 1; |
|
- | 687 | i2 = (x >> 22) & 1; |
|
- | 688 | j1 = s ^ (i1 ^ 1); |
|
- | 689 | j2 = s ^ (i2 ^ 1); |
|
- | 690 | imm10 = (x >> 12) & 0x3ff; |
|
- | 691 | imm11 = (x >> 1) & 0x7ff; |
|
- | 692 | (*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) | |
|
- | 693 | (s << 10) | imm10); |
|
- | 694 | (*(uint16_t *)(ptr+2)) = (uint16_t) ((lo & 0xc000) | |
|
- | 695 | (j1 << 13) | blx_bit | (j2 << 11) | |
|
- | 696 | imm11); |
|
- | 697 | } |
|
- | 698 | break; |
|
- | 699 | case R_ARM_MOVT_ABS: |
|
- | 700 | case R_ARM_MOVW_ABS_NC: |
|
- | 701 | { |
|
- | 702 | int x, imm4, imm12; |
|
- | 703 | if (type == R_ARM_MOVT_ABS) |
|
- | 704 | val >>= 16; |
|
- | 705 | imm12 = val & 0xfff; |
|
- | 706 | imm4 = (val >> 12) & 0xf; |
|
- | 707 | x = (imm4 << 16) | imm12; |
|
- | 708 | if (type == R_ARM_THM_MOVT_ABS) |
|
- | 709 | *(int *)ptr |= x; |
|
- | 710 | else |
|
- | 711 | *(int *)ptr += x; |
|
- | 712 | } |
|
- | 713 | break; |
|
- | 714 | case R_ARM_THM_MOVT_ABS: |
|
- | 715 | case R_ARM_THM_MOVW_ABS_NC: |
|
- | 716 | { |
|
- | 717 | int x, i, imm4, imm3, imm8; |
|
- | 718 | if (type == R_ARM_THM_MOVT_ABS) |
|
- | 719 | val >>= 16; |
|
- | 720 | imm8 = val & 0xff; |
|
- | 721 | imm3 = (val >> 8) & 0x7; |
|
- | 722 | i = (val >> 11) & 1; |
|
- | 723 | imm4 = (val >> 12) & 0xf; |
|
- | 724 | x = (imm3 << 28) | (imm8 << 16) | (i << 10) | imm4; |
|
- | 725 | if (type == R_ARM_THM_MOVT_ABS) |
|
- | 726 | *(int *)ptr |= x; |
|
- | 727 | else |
|
- | 728 | *(int *)ptr += x; |
|
- | 729 | } |
|
- | 730 | break; |
|
- | 731 | case R_ARM_PREL31: |
|
- | 732 | { |
|
- | 733 | int x; |
|
- | 734 | x = (*(int *)ptr) & 0x7fffffff; |
|
- | 735 | (*(int *)ptr) &= 0x80000000; |
|
528 | error("can't relocate value at %x",addr); |
736 | x = (x * 2) / 2; |
529 | x >>= 2; |
737 | x += val - addr; |
530 | x &= 0xffffff; |
738 | if((x^(x>>1))&0x40000000) |
- | 739 | tcc_error("can't relocate value at %x,%d",addr, type); |
|
- | 740 | (*(int *)ptr) |= x & 0x7fffffff; |
|
- | 741 | } |
|
531 | (*(int *)ptr) |= x; |
742 | case R_ARM_ABS32: |
532 | } |
743 | *(int *)ptr += val; |
533 | break; |
744 | break; |
- | 745 | case R_ARM_REL32: |
|
- | 746 | *(int *)ptr += val - addr; |
|
- | 747 | break; |
|
534 | case R_ARM_ABS32: |
748 | case R_ARM_GOTPC: |
535 | *(int *)ptr += val; |
749 | *(int *)ptr += s1->got->sh_addr - addr; |
536 | break; |
750 | break; |
537 | case R_ARM_GOTPC: |
751 | case R_ARM_GOTOFF: |
538 | *(int *)ptr += s1->got->sh_addr - addr; |
752 | *(int *)ptr += val - s1->got->sh_addr; |
539 | break; |
753 | break; |
- | 754 | case R_ARM_GOT32: |
|
- | 755 | /* we load the got offset */ |
|
- | 756 | *(int *)ptr += s1->sym_attrs[sym_index].got_offset; |
|
- | 757 | break; |
|
- | 758 | case R_ARM_COPY: |
|
- | 759 | break; |
|
- | 760 | case R_ARM_V4BX: |
|
- | 761 | /* trade Thumb support for ARMv4 support */ |
|
- | 762 | if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) |
|
- | 763 | *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ |
|
- | 764 | break; |
|
- | 765 | case R_ARM_GLOB_DAT: |
|
- | 766 | case R_ARM_JUMP_SLOT: |
|
- | 767 | *(addr_t *)ptr = val; |
|
- | 768 | break; |
|
- | 769 | case R_ARM_NONE: |
|
- | 770 | /* Nothing to do. Normally used to indicate a dependency |
|
- | 771 | on a certain symbol (like for exception handling under EABI). */ |
|
- | 772 | break; |
|
- | 773 | default: |
|
- | 774 | fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
|
- | 775 | type, (unsigned)addr, ptr, (unsigned)val); |
|
- | 776 | break; |
|
- | 777 | #elif defined(TCC_TARGET_ARM64) |
|
- | 778 | case R_AARCH64_ABS64: |
|
- | 779 | write64le(ptr, val); |
|
- | 780 | break; |
|
- | 781 | case R_AARCH64_ABS32: |
|
- | 782 | write32le(ptr, val); |
|
- | 783 | break; |
|
- | 784 | case R_AARCH64_MOVW_UABS_G0_NC: |
|
- | 785 | write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
|
- | 786 | (val & 0xffff) << 5)); |
|
- | 787 | break; |
|
- | 788 | case R_AARCH64_MOVW_UABS_G1_NC: |
|
- | 789 | write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
|
- | 790 | (val >> 16 & 0xffff) << 5)); |
|
- | 791 | break; |
|
- | 792 | case R_AARCH64_MOVW_UABS_G2_NC: |
|
- | 793 | write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
|
- | 794 | (val >> 32 & 0xffff) << 5)); |
|
- | 795 | break; |
|
- | 796 | case R_AARCH64_MOVW_UABS_G3: |
|
- | 797 | write32le(ptr, ((read32le(ptr) & 0xffe0001f) | |
|
- | 798 | (val >> 48 & 0xffff) << 5)); |
|
- | 799 | break; |
|
- | 800 | case R_AARCH64_ADR_PREL_PG_HI21: { |
|
- | 801 | uint64_t off = (val >> 12) - (addr >> 12); |
|
- | 802 | if ((off + ((uint64_t)1 << 20)) >> 21) |
|
- | 803 | tcc_error("R_AARCH64_ADR_PREL_PG_HI21 relocation failed"); |
|
- | 804 | write32le(ptr, ((read32le(ptr) & 0x9f00001f) | |
|
- | 805 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
|
- | 806 | break; |
|
- | 807 | } |
|
- | 808 | case R_AARCH64_ADD_ABS_LO12_NC: |
|
- | 809 | write32le(ptr, ((read32le(ptr) & 0xffc003ff) | |
|
- | 810 | (val & 0xfff) << 10)); |
|
- | 811 | break; |
|
- | 812 | case R_AARCH64_JUMP26: |
|
- | 813 | case R_AARCH64_CALL26: |
|
- | 814 | /* This check must match the one in build_got_entries, testing |
|
- | 815 | if we really need a PLT slot. */ |
|
- | 816 | if (sym->st_shndx == SHN_UNDEF) |
|
- | 817 | /* We've put the PLT slot offset into r_addend when generating |
|
- | 818 | it, and that's what we must use as relocation value (adjusted |
|
- | 819 | by section offset of course). */ |
|
- | 820 | val = s1->plt->sh_addr + rel->r_addend; |
|
- | 821 | #ifdef DEBUG_RELOC |
|
- | 822 | printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val, |
|
- | 823 | (char *) symtab_section->link->data + sym->st_name); |
|
- | 824 | #endif |
|
- | 825 | if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc) |
|
- | 826 | { |
|
- | 827 | tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val); |
|
- | 828 | } |
|
- | 829 | write32le(ptr, (0x14000000 | |
|
- | 830 | (uint32_t)(type == R_AARCH64_CALL26) << 31 | |
|
- | 831 | ((val - addr) >> 2 & 0x3ffffff))); |
|
- | 832 | break; |
|
- | 833 | case R_AARCH64_ADR_GOT_PAGE: { |
|
- | 834 | uint64_t off = |
|
- | 835 | (((s1->got->sh_addr + |
|
- | 836 | s1->sym_attrs[sym_index].got_offset) >> 12) - (addr >> 12)); |
|
- | 837 | if ((off + ((uint64_t)1 << 20)) >> 21) |
|
- | 838 | tcc_error("R_AARCH64_ADR_GOT_PAGE relocation failed"); |
|
- | 839 | write32le(ptr, ((read32le(ptr) & 0x9f00001f) | |
|
- | 840 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
|
- | 841 | break; |
|
- | 842 | } |
|
- | 843 | case R_AARCH64_LD64_GOT_LO12_NC: |
|
- | 844 | write32le(ptr, |
|
- | 845 | ((read32le(ptr) & 0xfff803ff) | |
|
- | 846 | ((s1->got->sh_addr + |
|
- | 847 | s1->sym_attrs[sym_index].got_offset) & 0xff8) << 7)); |
|
- | 848 | break; |
|
- | 849 | case R_AARCH64_COPY: |
|
- | 850 | break; |
|
- | 851 | case R_AARCH64_GLOB_DAT: |
|
- | 852 | case R_AARCH64_JUMP_SLOT: |
|
- | 853 | /* They don't need addend */ |
|
- | 854 | #ifdef DEBUG_RELOC |
|
540 | case R_ARM_GOT32: |
855 | printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, |
541 | /* we load the got offset */ |
856 | val - rel->r_addend, |
542 | *(int *)ptr += s1->got_offsets[sym_index]; |
857 | (char *) symtab_section->link->data + sym->st_name); |
543 | break; |
858 | #endif |
544 | case R_ARM_COPY: |
859 | write64le(ptr, val - rel->r_addend); |
545 | break; |
860 | break; |
546 | default: |
861 | default: |
547 | fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", |
862 | fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n", |
548 | type,addr,(unsigned int )ptr,val); |
863 | type, (unsigned)addr, ptr, (unsigned)val); |
549 | break; |
864 | break; |
550 | #elif defined(TCC_TARGET_C67) |
865 | #elif defined(TCC_TARGET_C67) |
Line 551... | Line 866... | ||
551 | case R_C60_32: |
866 | case R_C60_32: |
552 | *(int *)ptr += val; |
867 | *(int *)ptr += val; |
Line 553... | Line 868... | ||
553 | break; |
868 | break; |
554 | case R_C60LO16: |
869 | case R_C60LO16: |
Line 555... | Line 870... | ||
555 | { |
870 | { |
Line 556... | Line 871... | ||
556 | uint32_t orig; |
871 | uint32_t orig; |
557 | 872 | ||
558 | /* put the low 16 bits of the absolute address */ |
873 | /* put the low 16 bits of the absolute address |
559 | // add to what is already there |
874 | add to what is already there */ |
560 | 875 | ||
561 | orig = ((*(int *)(ptr )) >> 7) & 0xffff; |
876 | orig = ((*(int *)(ptr )) >> 7) & 0xffff; |
562 | orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; |
877 | orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; |
563 | 878 | ||
564 | //patch both at once - assumes always in pairs Low - High |
879 | /* patch both at once - assumes always in pairs Low - High */ |
- | 880 | ||
- | 881 | *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); |
|
- | 882 | *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); |
|
- | 883 | } |
|
- | 884 | break; |
|
- | 885 | case R_C60HI16: |
|
- | 886 | break; |
|
- | 887 | default: |
|
- | 888 | fprintf(stderr,"FIXME: handle reloc type %x at %x [%p] to %x\n", |
|
- | 889 | type, (unsigned)addr, ptr, (unsigned)val); |
|
- | 890 | break; |
|
- | 891 | #elif defined(TCC_TARGET_X86_64) |
|
- | 892 | case R_X86_64_64: |
|
- | 893 | if (s1->output_type == TCC_OUTPUT_DLL) { |
|
- | 894 | esym_index = s1->symtab_to_dynsym[sym_index]; |
|
- | 895 | qrel->r_offset = rel->r_offset; |
|
- | 896 | if (esym_index) { |
|
- | 897 | qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); |
|
- | 898 | qrel->r_addend = rel->r_addend; |
|
- | 899 | qrel++; |
|
- | 900 | break; |
|
- | 901 | } else { |
|
- | 902 | qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
|
- | 903 | qrel->r_addend = read64le(ptr) + val; |
|
- | 904 | qrel++; |
|
- | 905 | } |
|
- | 906 | } |
|
- | 907 | write64le(ptr, read64le(ptr) + val); |
|
- | 908 | break; |
|
- | 909 | case R_X86_64_32: |
|
- | 910 | case R_X86_64_32S: |
|
- | 911 | if (s1->output_type == TCC_OUTPUT_DLL) { |
|
- | 912 | /* XXX: this logic may depend on TCC's codegen |
|
- | 913 | now TCC uses R_X86_64_32 even for a 64bit pointer */ |
|
- | 914 | qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
|
- | 915 | /* Use sign extension! */ |
|
- | 916 | qrel->r_addend = (int)read32le(ptr) + val; |
|
- | 917 | qrel++; |
|
- | 918 | } |
|
- | 919 | write32le(ptr, read32le(ptr) + val); |
|
- | 920 | break; |
|
- | 921 | ||
- | 922 | case R_X86_64_PC32: |
|
- | 923 | if (s1->output_type == TCC_OUTPUT_DLL) { |
|
- | 924 | /* DLL relocation */ |
|
- | 925 | esym_index = s1->symtab_to_dynsym[sym_index]; |
|
- | 926 | if (esym_index) { |
|
- | 927 | qrel->r_offset = rel->r_offset; |
|
- | 928 | qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); |
|
- | 929 | /* Use sign extension! */ |
|
- | 930 | qrel->r_addend = (int)read32le(ptr); |
|
- | 931 | qrel++; |
|
- | 932 | break; |
|
- | 933 | } |
|
- | 934 | } |
|
- | 935 | goto plt32pc32; |
|
- | 936 | ||
- | 937 | case R_X86_64_PLT32: |
|
- | 938 | /* We've put the PLT slot offset into r_addend when generating |
|
- | 939 | it, and that's what we must use as relocation value (adjusted |
|
- | 940 | by section offset of course). */ |
|
- | 941 | val = s1->plt->sh_addr + rel->r_addend; |
|
- | 942 | /* fallthrough. */ |
|
- | 943 | ||
- | 944 | plt32pc32: |
|
- | 945 | { |
|
- | 946 | long long diff; |
|
- | 947 | diff = (long long)val - addr; |
|
- | 948 | if (diff < -2147483648LL || diff > 2147483647LL) { |
|
- | 949 | tcc_error("internal error: relocation failed"); |
|
- | 950 | } |
|
- | 951 | write32le(ptr, read32le(ptr) + diff); |
|
- | 952 | } |
|
- | 953 | break; |
|
- | 954 | case R_X86_64_GLOB_DAT: |
|
- | 955 | case R_X86_64_JUMP_SLOT: |
|
- | 956 | /* They don't need addend */ |
|
- | 957 | write64le(ptr, val - rel->r_addend); |
|
- | 958 | break; |
|
- | 959 | case R_X86_64_GOTPCREL: |
|
- | 960 | case R_X86_64_GOTPCRELX: |
|
- | 961 | case R_X86_64_REX_GOTPCRELX: |
|
565 | 962 | write32le(ptr, read32le(ptr) + |
|
566 | *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); |
963 | (s1->got->sh_addr - addr + |
567 | *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); |
964 | s1->sym_attrs[sym_index].got_offset - 4)); |
568 | } |
965 | break; |
569 | break; |
966 | case R_X86_64_GOTTPOFF: |
Line 585... | Line 982... | ||
585 | 982 | ||
586 | /* relocate relocation table in 'sr' */ |
983 | /* relocate relocation table in 'sr' */ |
587 | static void relocate_rel(TCCState *s1, Section *sr) |
984 | static void relocate_rel(TCCState *s1, Section *sr) |
588 | { |
985 | { |
589 | Section *s; |
986 | Section *s; |
Line 590... | Line 987... | ||
590 | Elf32_Rel *rel, *rel_end; |
987 | ElfW_Rel *rel; |
591 | - | ||
592 | s = s1->sections[sr->sh_info]; |
988 | |
593 | rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
- | |
594 | for(rel = (Elf32_Rel *)sr->data; |
- | |
595 | rel < rel_end; |
989 | s = s1->sections[sr->sh_info]; |
596 | rel++) { |
990 | for_each_elem(sr, 0, rel, ElfW_Rel) |
597 | rel->r_offset += s->sh_addr; |
- | |
Line 598... | Line 991... | ||
598 | } |
991 | rel->r_offset += s->sh_addr; |
599 | } |
992 | } |
600 | 993 | ||
601 | /* count the number of dynamic relocations so that we can reserve |
994 | /* count the number of dynamic relocations so that we can reserve |
602 | their space */ |
995 | their space */ |
603 | static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
996 | static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
Line 604... | Line 997... | ||
604 | { |
997 | { |
605 | Elf32_Rel *rel, *rel_end; |
- | |
606 | int sym_index, esym_index, type, count; |
998 | ElfW_Rel *rel; |
607 | 999 | int sym_index, esym_index, type, count; |
|
608 | count = 0; |
1000 | |
609 | rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
1001 | count = 0; |
- | 1002 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
|
610 | for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++) { |
1003 | sym_index = ELFW(R_SYM)(rel->r_info); |
- | 1004 | type = ELFW(R_TYPE)(rel->r_info); |
|
- | 1005 | switch(type) { |
|
- | 1006 | #if defined(TCC_TARGET_I386) |
|
- | 1007 | case R_386_32: |
|
- | 1008 | #elif defined(TCC_TARGET_X86_64) |
|
611 | sym_index = ELF32_R_SYM(rel->r_info); |
1009 | case R_X86_64_32: |
612 | type = ELF32_R_TYPE(rel->r_info); |
1010 | case R_X86_64_32S: |
- | 1011 | case R_X86_64_64: |
|
613 | switch(type) { |
1012 | #endif |
- | 1013 | count++; |
|
- | 1014 | break; |
|
- | 1015 | #if defined(TCC_TARGET_I386) |
|
614 | case R_386_32: |
1016 | case R_386_PC32: |
615 | count++; |
1017 | #elif defined(TCC_TARGET_X86_64) |
616 | break; |
1018 | case R_X86_64_PC32: |
617 | case R_386_PC32: |
1019 | #endif |
618 | esym_index = s1->symtab_to_dynsym[sym_index]; |
1020 | esym_index = s1->symtab_to_dynsym[sym_index]; |
Line 624... | Line 1026... | ||
624 | } |
1026 | } |
625 | } |
1027 | } |
626 | if (count) { |
1028 | if (count) { |
627 | /* allocate the section */ |
1029 | /* allocate the section */ |
628 | sr->sh_flags |= SHF_ALLOC; |
1030 | sr->sh_flags |= SHF_ALLOC; |
629 | sr->sh_size = count * sizeof(Elf32_Rel); |
1031 | sr->sh_size = count * sizeof(ElfW_Rel); |
630 | } |
1032 | } |
631 | return count; |
1033 | return count; |
632 | } |
1034 | } |
Line 633... | Line 1035... | ||
633 | 1035 | ||
634 | static void put_got_offset(TCCState *s1, int index, unsigned long val) |
1036 | static struct sym_attr *alloc_sym_attr(TCCState *s1, int index) |
635 | { |
1037 | { |
636 | int n; |
1038 | int n; |
Line 637... | Line 1039... | ||
637 | unsigned long *tab; |
1039 | struct sym_attr *tab; |
638 | 1040 | ||
639 | if (index >= s1->nb_got_offsets) { |
1041 | if (index >= s1->nb_sym_attrs) { |
640 | /* find immediately bigger power of 2 and reallocate array */ |
1042 | /* find immediately bigger power of 2 and reallocate array */ |
641 | n = 1; |
1043 | n = 1; |
642 | while (index >= n) |
1044 | while (index >= n) |
643 | n *= 2; |
- | |
644 | tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long)); |
- | |
645 | if (!tab) |
1045 | n *= 2; |
646 | error("memory full"); |
1046 | tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); |
647 | s1->got_offsets = tab; |
1047 | s1->sym_attrs = tab; |
648 | memset(s1->got_offsets + s1->nb_got_offsets, 0, |
1048 | memset(s1->sym_attrs + s1->nb_sym_attrs, 0, |
649 | (n - s1->nb_got_offsets) * sizeof(unsigned long)); |
- | |
650 | s1->nb_got_offsets = n; |
- | |
651 | } |
- | |
652 | s1->got_offsets[index] = val; |
- | |
653 | } |
- | |
654 | - | ||
655 | /* XXX: suppress that */ |
- | |
656 | static void put32(unsigned char *p, uint32_t val) |
- | |
657 | { |
- | |
658 | p[0] = val; |
- | |
659 | p[1] = val >> 8; |
- | |
660 | p[2] = val >> 16; |
1049 | (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); |
661 | p[3] = val >> 24; |
- | |
662 | } |
- | |
663 | 1050 | s1->nb_sym_attrs = n; |
|
664 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) |
- | |
665 | static uint32_t get32(unsigned char *p) |
- | |
666 | { |
1051 | } |
667 | return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); |
- | |
Line 668... | Line 1052... | ||
668 | } |
1052 | return &s1->sym_attrs[index]; |
669 | #endif |
1053 | } |
670 | 1054 | ||
Line 671... | Line 1055... | ||
671 | static void build_got(TCCState *s1) |
1055 | static void build_got(TCCState *s1) |
672 | { |
1056 | { |
673 | unsigned char *ptr; |
1057 | unsigned char *ptr; |
674 | 1058 | ||
675 | /* if no got, then create it */ |
1059 | /* if no got, then create it */ |
676 | s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
1060 | s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
- | 1061 | s1->got->sh_entsize = 4; |
|
- | 1062 | add_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
|
- | 1063 | 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); |
|
- | 1064 | ptr = section_ptr_add(s1->got, 3 * PTR_SIZE); |
|
- | 1065 | #if PTR_SIZE == 4 |
|
- | 1066 | /* keep space for _DYNAMIC pointer, if present */ |
|
- | 1067 | write32le(ptr, 0); |
|
677 | s1->got->sh_entsize = 4; |
1068 | /* two dummy got entries */ |
678 | add_elf_sym(symtab_section, 0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), |
1069 | write32le(ptr + 4, 0); |
- | 1070 | write32le(ptr + 8, 0); |
|
679 | 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); |
1071 | #else |
680 | ptr = section_ptr_add(s1->got, 3 * sizeof(int)); |
1072 | /* keep space for _DYNAMIC pointer, if present */ |
- | 1073 | write32le(ptr, 0); |
|
681 | /* keep space for _DYNAMIC pointer, if present */ |
1074 | write32le(ptr + 4, 0); |
- | 1075 | /* two dummy got entries */ |
|
- | 1076 | write32le(ptr + 8, 0); |
|
682 | put32(ptr, 0); |
1077 | write32le(ptr + 12, 0); |
Line 683... | Line 1078... | ||
683 | /* two dummy got entries */ |
1078 | write32le(ptr + 16, 0); |
684 | put32(ptr + 4, 0); |
1079 | write32le(ptr + 20, 0); |
- | 1080 | #endif |
|
685 | put32(ptr + 8, 0); |
1081 | } |
686 | } |
1082 | |
687 | 1083 | /* put a got or plt entry corresponding to a symbol in symtab_section. 'size' |
|
688 | /* put a got entry corresponding to a symbol in symtab_section. 'size' |
1084 | and 'info' can be modifed if more precise info comes from the DLL. |
689 | and 'info' can be modifed if more precise info comes from the DLL */ |
1085 | Returns offset of GOT or PLT slot. */ |
690 | static void put_got_entry(TCCState *s1, |
1086 | static unsigned long put_got_entry(TCCState *s1, |
691 | int reloc_type, unsigned long size, int info, |
1087 | int reloc_type, unsigned long size, int info, |
692 | int sym_index) |
1088 | int sym_index) |
693 | { |
1089 | { |
- | 1090 | int index, need_plt_entry; |
|
Line 694... | Line 1091... | ||
694 | int index; |
1091 | const char *name; |
695 | const char *name; |
1092 | ElfW(Sym) *sym; |
Line -... | Line 1093... | ||
- | 1093 | unsigned long offset; |
|
- | 1094 | int *ptr; |
|
696 | Elf32_Sym *sym; |
1095 | struct sym_attr *symattr; |
- | 1096 | ||
697 | unsigned long offset; |
1097 | if (!s1->got) |
- | 1098 | build_got(s1); |
|
698 | int *ptr; |
1099 | |
- | 1100 | need_plt_entry = |
|
- | 1101 | #ifdef TCC_TARGET_X86_64 |
|
- | 1102 | (reloc_type == R_X86_64_JUMP_SLOT); |
|
699 | 1103 | #elif defined(TCC_TARGET_I386) |
|
- | 1104 | (reloc_type == R_386_JMP_SLOT); |
|
Line -... | Line 1105... | ||
- | 1105 | #elif defined(TCC_TARGET_ARM) |
|
- | 1106 | (reloc_type == R_ARM_JUMP_SLOT); |
|
700 | if (!s1->got) |
1107 | #elif defined(TCC_TARGET_ARM64) |
- | 1108 | (reloc_type == R_AARCH64_JUMP_SLOT); |
|
- | 1109 | #else |
|
- | 1110 | 0; |
|
Line -... | Line 1111... | ||
- | 1111 | #endif |
|
- | 1112 | ||
- | 1113 | if (need_plt_entry && !s1->plt) { |
|
- | 1114 | /* add PLT */ |
|
- | 1115 | s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
|
- | 1116 | SHF_ALLOC | SHF_EXECINSTR); |
|
- | 1117 | s1->plt->sh_entsize = 4; |
|
- | 1118 | } |
|
- | 1119 | ||
- | 1120 | /* If a got/plt entry already exists for that symbol, no need to add one */ |
|
- | 1121 | if (sym_index < s1->nb_sym_attrs) { |
|
701 | build_got(s1); |
1122 | if (need_plt_entry && s1->sym_attrs[sym_index].plt_offset) |
- | 1123 | return s1->sym_attrs[sym_index].plt_offset; |
|
- | 1124 | else if (!need_plt_entry && s1->sym_attrs[sym_index].got_offset) |
|
702 | 1125 | return s1->sym_attrs[sym_index].got_offset; |
|
703 | /* if a got entry already exists for that symbol, no need to add one */ |
1126 | } |
704 | if (sym_index < s1->nb_got_offsets && |
1127 | |
705 | s1->got_offsets[sym_index] != 0) |
1128 | symattr = alloc_sym_attr(s1, sym_index); |
706 | return; |
1129 | |
707 | 1130 | /* Only store the GOT offset if it's not generated for the PLT entry. */ |
|
708 | put_got_offset(s1, sym_index, s1->got->data_offset); |
1131 | if (!need_plt_entry) |
709 | 1132 | symattr->got_offset = s1->got->data_offset; |
|
- | 1133 | ||
Line -... | Line 1134... | ||
- | 1134 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1135 | name = (char *) symtab_section->link->data + sym->st_name; |
|
- | 1136 | offset = sym->st_value; |
|
710 | if (s1->dynsym) { |
1137 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
711 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
1138 | if (need_plt_entry) { |
712 | name = symtab_section->link->data + sym->st_name; |
1139 | Section *plt; |
713 | offset = sym->st_value; |
1140 | uint8_t *p; |
714 | #ifdef TCC_TARGET_I386 |
1141 | int modrm; |
- | 1142 | unsigned long relofs; |
|
Line 715... | Line 1143... | ||
715 | if (reloc_type == R_386_JMP_SLOT) { |
1143 | |
716 | Section *plt; |
1144 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) |
717 | uint8_t *p; |
1145 | modrm = 0x25; |
718 | int modrm; |
1146 | #else |
719 | 1147 | /* if we build a DLL, we add a %ebx offset */ |
|
720 | /* if we build a DLL, we add a %ebx offset */ |
1148 | if (s1->output_type == TCC_OUTPUT_DLL) |
721 | if (s1->output_type == TCC_OUTPUT_DLL) |
1149 | modrm = 0xa3; |
722 | modrm = 0xa3; |
1150 | else |
723 | else |
1151 | modrm = 0x25; |
724 | modrm = 0x25; |
1152 | #endif |
725 | 1153 | ||
726 | /* add a PLT entry */ |
1154 | /* add a PLT entry */ |
Line -... | Line 1155... | ||
- | 1155 | plt = s1->plt; |
|
- | 1156 | if (plt->data_offset == 0) { |
|
- | 1157 | /* first plt entry */ |
|
- | 1158 | p = section_ptr_add(plt, 16); |
|
- | 1159 | p[0] = 0xff; /* pushl got + PTR_SIZE */ |
|
727 | plt = s1->plt; |
1160 | p[1] = modrm + 0x10; |
728 | if (plt->data_offset == 0) { |
1161 | write32le(p + 2, PTR_SIZE); |
729 | /* first plt entry */ |
1162 | p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ |
730 | p = section_ptr_add(plt, 16); |
1163 | p[7] = modrm; |
731 | p[0] = 0xff; /* pushl got + 4 */ |
1164 | write32le(p + 8, PTR_SIZE * 2); |
- | 1165 | } |
|
- | 1166 | ||
- | 1167 | /* The PLT slot refers to the relocation entry it needs |
|
- | 1168 | via offset. The reloc entry is created below, so its |
|
732 | p[1] = modrm + 0x10; |
1169 | offset is the current data_offset. */ |
- | 1170 | relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; |
|
733 | put32(p + 2, 4); |
1171 | symattr->plt_offset = plt->data_offset; |
734 | p[6] = 0xff; /* jmp *(got + 8) */ |
1172 | p = section_ptr_add(plt, 16); |
Line -... | Line 1173... | ||
- | 1173 | p[0] = 0xff; /* jmp *(got + x) */ |
|
735 | p[7] = modrm; |
1174 | p[1] = modrm; |
736 | put32(p + 8, 8); |
1175 | write32le(p + 2, s1->got->data_offset); |
737 | } |
1176 | p[6] = 0x68; /* push $xxx */ |
738 | 1177 | #ifdef TCC_TARGET_X86_64 |
|
739 | p = section_ptr_add(plt, 16); |
1178 | /* On x86-64, the relocation is referred to by _index_. */ |
740 | p[0] = 0xff; /* jmp *(got + x) */ |
1179 | write32le(p + 7, relofs / sizeof (ElfW_Rel)); |
741 | p[1] = modrm; |
1180 | #else |
742 | put32(p + 2, s1->got->data_offset); |
1181 | write32le(p + 7, relofs); |
743 | p[6] = 0x68; /* push $xxx */ |
1182 | #endif |
Line 744... | Line 1183... | ||
744 | put32(p + 7, (plt->data_offset - 32) >> 1); |
1183 | p[11] = 0xe9; /* jmp plt_start */ |
745 | p[11] = 0xe9; /* jmp plt_start */ |
1184 | write32le(p + 12, -(plt->data_offset)); |
746 | put32(p + 12, -(plt->data_offset)); |
1185 | |
Line 747... | Line 1186... | ||
747 | 1186 | /* If this was an UNDEF symbol set the offset in the |
|
748 | /* the symbol is modified so that it will be relocated to |
1187 | dynsymtab to the PLT slot, so that PC32 relocs to it |
749 | the PLT */ |
1188 | can be resolved. */ |
750 | if (s1->output_type == TCC_OUTPUT_EXE) |
1189 | if (sym->st_shndx == SHN_UNDEF) |
751 | offset = plt->data_offset - 16; |
1190 | offset = plt->data_offset - 16; |
752 | } |
1191 | } |
753 | #elif defined(TCC_TARGET_ARM) |
1192 | #elif defined(TCC_TARGET_ARM) |
754 | if (reloc_type == R_ARM_JUMP_SLOT) { |
1193 | if (need_plt_entry) { |
755 | Section *plt; |
1194 | Section *plt; |
756 | uint8_t *p; |
1195 | uint8_t *p; |
Line -... | Line 1196... | ||
- | 1196 | ||
- | 1197 | /* if we build a DLL, we add a %ebx offset */ |
|
- | 1198 | if (s1->output_type == TCC_OUTPUT_DLL) |
|
- | 1199 | tcc_error("DLLs unimplemented!"); |
|
- | 1200 | ||
- | 1201 | /* add a PLT entry */ |
|
- | 1202 | plt = s1->plt; |
|
757 | 1203 | if (plt->data_offset == 0) { |
|
758 | /* if we build a DLL, we add a %ebx offset */ |
1204 | /* first plt entry */ |
759 | if (s1->output_type == TCC_OUTPUT_DLL) |
1205 | p = section_ptr_add(plt, 16); |
760 | error("DLLs unimplemented!"); |
1206 | write32le(p, 0xe52de004); /* push {lr} */ |
761 | 1207 | write32le(p+4, 0xe59fe010); /* ldr lr, [pc, #16] */ |
|
Line 762... | Line 1208... | ||
762 | /* add a PLT entry */ |
1208 | write32le(p+8, 0xe08fe00e); /* add lr, pc, lr */ |
763 | plt = s1->plt; |
1209 | write32le(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ |
- | 1210 | } |
|
- | 1211 | ||
- | 1212 | symattr->plt_offset = plt->data_offset; |
|
- | 1213 | if (symattr->plt_thumb_stub) { |
|
- | 1214 | p = section_ptr_add(plt, 20); |
|
- | 1215 | write32le(p, 0x4778); /* bx pc */ |
|
- | 1216 | write32le(p+2, 0x46c0); /* nop */ |
|
- | 1217 | p += 4; |
|
764 | if (plt->data_offset == 0) { |
1218 | } else |
- | 1219 | p = section_ptr_add(plt, 16); |
|
- | 1220 | write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] ; GOT entry offset */ |
|
- | 1221 | write32le(p+4, 0xe08fc00c); /* add ip, pc, ip ; addr of GOT entry */ |
|
- | 1222 | write32le(p+8, 0xe59cf000); /* ldr pc, [ip] ; jump to GOT entry */ |
|
- | 1223 | write32le(p+12, s1->got->data_offset); /* GOT entry off once patched */ |
|
- | 1224 | ||
- | 1225 | /* the symbol is modified so that it will be relocated to |
|
- | 1226 | the PLT */ |
|
- | 1227 | if (sym->st_shndx == SHN_UNDEF) |
|
- | 1228 | offset = plt->data_offset - 16; |
|
- | 1229 | } |
|
765 | /* first plt entry */ |
1230 | #elif defined(TCC_TARGET_ARM64) |
766 | p = section_ptr_add(plt, 16); |
1231 | if (need_plt_entry) { |
767 | put32(p , 0xe52de004); |
1232 | Section *plt; |
- | 1233 | uint8_t *p; |
|
768 | put32(p + 4, 0xe59fe010); |
1234 | |
- | 1235 | if (s1->output_type == TCC_OUTPUT_DLL) |
|
769 | put32(p + 8, 0xe08fe00e); |
1236 | tcc_error("DLLs unimplemented!"); |
770 | put32(p + 12, 0xe5bef008); |
1237 | |
771 | } |
1238 | plt = s1->plt; |
- | 1239 | if (plt->data_offset == 0) |
|
- | 1240 | section_ptr_add(plt, 32); |
|
772 | 1241 | symattr->plt_offset = plt->data_offset; |
|
773 | p = section_ptr_add(plt, 16); |
1242 | p = section_ptr_add(plt, 16); |
- | 1243 | write32le(p, s1->got->data_offset); |
|
774 | put32(p , 0xe59fc004); |
1244 | write32le(p + 4, (uint64_t)s1->got->data_offset >> 32); |
775 | put32(p+4, 0xe08fc00c); |
1245 | |
776 | put32(p+8, 0xe59cf000); |
1246 | if (sym->st_shndx == SHN_UNDEF) |
777 | put32(p+12, s1->got->data_offset); |
1247 | offset = plt->data_offset - 16; |
- | 1248 | } |
|
- | 1249 | #elif defined(TCC_TARGET_C67) |
|
- | 1250 | if (s1->dynsym) { |
|
- | 1251 | tcc_error("C67 got not implemented"); |
|
- | 1252 | } |
|
- | 1253 | #else |
|
- | 1254 | #error unsupported CPU |
|
778 | 1255 | #endif |
|
- | 1256 | if (s1->dynsym) { |
|
779 | /* the symbol is modified so that it will be relocated to |
1257 | /* XXX This might generate multiple syms for name. */ |
780 | the PLT */ |
1258 | index = put_elf_sym(s1->dynsym, offset, |
- | 1259 | size, info, 0, sym->st_shndx, name); |
|
- | 1260 | /* Create the relocation (it's against the GOT for PLT |
|
- | 1261 | and GOT relocs). */ |
|
- | 1262 | put_elf_reloc(s1->dynsym, s1->got, |
|
781 | if (s1->output_type == TCC_OUTPUT_EXE) |
1263 | s1->got->data_offset, |
Line 782... | Line 1264... | ||
782 | offset = plt->data_offset - 16; |
1264 | reloc_type, index); |
783 | } |
1265 | } else { |
784 | #elif defined(TCC_TARGET_C67) |
1266 | /* Without .dynsym (i.e. static link or memory output) we |
785 | error("C67 got not implemented"); |
1267 | still need relocs against the generated got, so as to fill |
786 | #else |
1268 | the entries with the symbol values (determined later). */ |
787 | #error unsupported CPU |
1269 | put_elf_reloc(symtab_section, s1->got, |
788 | #endif |
1270 | s1->got->data_offset, |
Line 789... | Line 1271... | ||
789 | index = put_elf_sym(s1->dynsym, offset, |
1271 | reloc_type, sym_index); |
790 | size, info, 0, sym->st_shndx, name); |
1272 | } |
791 | /* put a got entry */ |
1273 | /* And now create the GOT slot itself. */ |
792 | put_elf_reloc(s1->dynsym, s1->got, |
1274 | ptr = section_ptr_add(s1->got, PTR_SIZE); |
793 | s1->got->data_offset, |
1275 | *ptr = 0; |
794 | reloc_type, index); |
1276 | if (need_plt_entry) |
795 | } |
1277 | return symattr->plt_offset; |
796 | ptr = section_ptr_add(s1->got, sizeof(int)); |
- | |
797 | *ptr = 0; |
- | |
798 | } |
1278 | else |
799 | - | ||
800 | /* build GOT and PLT entries */ |
- | |
801 | static void build_got_entries(TCCState *s1) |
1279 | return symattr->got_offset; |
802 | { |
1280 | } |
803 | Section *s, *symtab; |
1281 | |
804 | Elf32_Rel *rel, *rel_end; |
1282 | /* build GOT and PLT entries */ |
- | 1283 | ST_FUNC void build_got_entries(TCCState *s1) |
|
805 | Elf32_Sym *sym; |
1284 | { |
806 | int i, type, reloc_type, sym_index; |
1285 | Section *s; |
807 | 1286 | ElfW_Rel *rel; |
|
808 | for(i = 1; i < s1->nb_sections; i++) { |
1287 | ElfW(Sym) *sym; |
809 | s = s1->sections[i]; |
1288 | int i, type, reloc_type, sym_index; |
810 | if (s->sh_type != SHT_REL) |
1289 | |
- | 1290 | for(i = 1; i < s1->nb_sections; i++) { |
|
811 | continue; |
1291 | s = s1->sections[i]; |
812 | /* no need to handle got relocations */ |
1292 | if (s->sh_type != SHT_RELX) |
813 | if (s->link != symtab_section) |
1293 | continue; |
814 | continue; |
1294 | /* no need to handle got relocations */ |
815 | symtab = s->link; |
1295 | if (s->link != symtab_section) |
816 | rel_end = (Elf32_Rel *)(s->data + s->data_offset); |
1296 | continue; |
817 | for(rel = (Elf32_Rel *)s->data; |
1297 | for_each_elem(s, 0, rel, ElfW_Rel) { |
818 | rel < rel_end; |
1298 | type = ELFW(R_TYPE)(rel->r_info); |
819 | rel++) { |
1299 | switch(type) { |
820 | type = ELF32_R_TYPE(rel->r_info); |
1300 | #if defined(TCC_TARGET_I386) |
821 | switch(type) { |
1301 | case R_386_GOT32: |
822 | #if defined(TCC_TARGET_I386) |
1302 | case R_386_GOT32X: |
- | 1303 | case R_386_GOTOFF: |
|
- | 1304 | case R_386_GOTPC: |
|
- | 1305 | case R_386_PLT32: |
|
823 | case R_386_GOT32: |
1306 | if (!s1->got) |
824 | case R_386_GOTOFF: |
1307 | build_got(s1); |
825 | case R_386_GOTPC: |
1308 | if (type == R_386_GOT32 || type == R_386_GOT32X || |
826 | case R_386_PLT32: |
1309 | type == R_386_PLT32) { |
827 | if (!s1->got) |
1310 | sym_index = ELFW(R_SYM)(rel->r_info); |
828 | build_got(s1); |
1311 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
829 | if (type == R_386_GOT32 || type == R_386_PLT32) { |
- | |
830 | sym_index = ELF32_R_SYM(rel->r_info); |
1312 | /* look at the symbol got offset. If none, then add one */ |
831 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
1313 | if (type == R_386_GOT32 || type == R_386_GOT32X) |
- | 1314 | reloc_type = R_386_GLOB_DAT; |
|
- | 1315 | else |
|
- | 1316 | reloc_type = R_386_JMP_SLOT; |
|
832 | /* look at the symbol got offset. If none, then add one */ |
1317 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
833 | if (type == R_386_GOT32) |
1318 | sym_index); |
834 | reloc_type = R_386_GLOB_DAT; |
1319 | } |
835 | else |
1320 | break; |
836 | reloc_type = R_386_JMP_SLOT; |
1321 | #elif defined(TCC_TARGET_ARM) |
- | 1322 | case R_ARM_PC24: |
|
- | 1323 | case R_ARM_CALL: |
|
- | 1324 | case R_ARM_JUMP24: |
|
- | 1325 | case R_ARM_GOT32: |
|
- | 1326 | case R_ARM_GOTOFF: |
|
- | 1327 | case R_ARM_GOTPC: |
|
- | 1328 | case R_ARM_PLT32: |
|
- | 1329 | if (!s1->got) |
|
- | 1330 | build_got(s1); |
|
- | 1331 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
- | 1332 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1333 | if (type != R_ARM_GOTOFF && type != R_ARM_GOTPC |
|
- | 1334 | && sym->st_shndx == SHN_UNDEF) { |
|
- | 1335 | unsigned long ofs; |
|
- | 1336 | /* look at the symbol got offset. If none, then add one */ |
|
- | 1337 | if (type == R_ARM_GOT32) |
|
- | 1338 | reloc_type = R_ARM_GLOB_DAT; |
|
- | 1339 | else |
|
- | 1340 | reloc_type = R_ARM_JUMP_SLOT; |
|
- | 1341 | ofs = put_got_entry(s1, reloc_type, sym->st_size, |
|
- | 1342 | sym->st_info, sym_index); |
|
- | 1343 | #ifdef DEBUG_RELOC |
|
- | 1344 | printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", |
|
- | 1345 | (char *) symtab_section->link->data + sym->st_name, |
|
- | 1346 | type, sym->st_shndx, ofs); |
|
- | 1347 | #endif |
|
- | 1348 | if (type != R_ARM_GOT32) { |
|
- | 1349 | addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data |
|
- | 1350 | + rel->r_offset); |
|
- | 1351 | /* x must be signed! */ |
|
- | 1352 | int x = *ptr & 0xffffff; |
|
- | 1353 | x = (x << 8) >> 8; |
|
- | 1354 | x <<= 2; |
|
- | 1355 | x += ofs; |
|
- | 1356 | x >>= 2; |
|
- | 1357 | #ifdef DEBUG_RELOC |
|
- | 1358 | printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, |
|
- | 1359 | (*ptr & 0xff000000) | x, x); |
|
- | 1360 | #endif |
|
- | 1361 | *ptr = (*ptr & 0xff000000) | x; |
|
- | 1362 | } |
|
- | 1363 | } |
|
- | 1364 | break; |
|
- | 1365 | case R_ARM_THM_JUMP24: |
|
- | 1366 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
- | 1367 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1368 | /* We are relocating a jump from thumb code to arm code */ |
|
- | 1369 | if (sym->st_shndx != SHN_UNDEF && !(sym->st_value & 1)) { |
|
- | 1370 | int index; |
|
- | 1371 | uint8_t *p; |
|
- | 1372 | char *name, buf[1024]; |
|
- | 1373 | Section *text_section; |
|
- | 1374 | ||
- | 1375 | name = (char *) symtab_section->link->data + sym->st_name; |
|
- | 1376 | text_section = s1->sections[sym->st_shndx]; |
|
- | 1377 | /* Modify reloc to target a thumb stub to switch to ARM */ |
|
- | 1378 | snprintf(buf, sizeof(buf), "%s_from_thumb", name); |
|
- | 1379 | index = put_elf_sym(symtab_section, |
|
- | 1380 | text_section->data_offset + 1, |
|
- | 1381 | sym->st_size, sym->st_info, 0, |
|
- | 1382 | sym->st_shndx, buf); |
|
837 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
1383 | rel->r_info = ELFW(R_INFO)(index, type); |
838 | sym_index); |
1384 | /* Create a thumb stub fonction to switch to ARM mode */ |
- | 1385 | put_elf_reloc(symtab_section, text_section, |
|
- | 1386 | text_section->data_offset + 4, R_ARM_JUMP24, |
|
- | 1387 | sym_index); |
|
- | 1388 | p = section_ptr_add(text_section, 8); |
|
- | 1389 | write32le(p, 0x4778); /* bx pc */ |
|
- | 1390 | write32le(p+2, 0x46c0); /* nop */ |
|
- | 1391 | write32le(p+4, 0xeafffffe); /* b $sym */ |
|
- | 1392 | } |
|
- | 1393 | #elif defined(TCC_TARGET_ARM64) |
|
- | 1394 | //xx Other cases may be required here: |
|
- | 1395 | case R_AARCH64_ADR_GOT_PAGE: |
|
- | 1396 | case R_AARCH64_LD64_GOT_LO12_NC: |
|
- | 1397 | if (!s1->got) |
|
- | 1398 | build_got(s1); |
|
- | 1399 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
- | 1400 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
839 | } |
1401 | reloc_type = R_AARCH64_GLOB_DAT; |
840 | break; |
1402 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
841 | #elif defined(TCC_TARGET_ARM) |
1403 | sym_index); |
842 | case R_ARM_GOT32: |
1404 | break; |
843 | case R_ARM_GOTOFF: |
1405 | |
844 | case R_ARM_GOTPC: |
1406 | case R_AARCH64_JUMP26: |
845 | case R_ARM_PLT32: |
1407 | case R_AARCH64_CALL26: |
846 | if (!s1->got) |
1408 | if (!s1->got) |
847 | build_got(s1); |
1409 | build_got(s1); |
848 | if (type == R_ARM_GOT32 || type == R_ARM_PLT32) { |
1410 | sym_index = ELFW(R_SYM)(rel->r_info); |
849 | sym_index = ELF32_R_SYM(rel->r_info); |
1411 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
850 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
1412 | if (sym->st_shndx == SHN_UNDEF) { |
851 | /* look at the symbol got offset. If none, then add one */ |
1413 | unsigned long ofs; |
852 | if (type == R_ARM_GOT32) |
1414 | reloc_type = R_AARCH64_JUMP_SLOT; |
853 | reloc_type = R_ARM_GLOB_DAT; |
1415 | ofs = put_got_entry(s1, reloc_type, sym->st_size, |
854 | else |
1416 | sym->st_info, sym_index); |
855 | reloc_type = R_ARM_JUMP_SLOT; |
1417 | /* We store the place of the generated PLT slot |
856 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
1418 | in our addend. */ |
857 | sym_index); |
1419 | rel->r_addend += ofs; |
858 | } |
1420 | } |
859 | break; |
1421 | break; |
- | 1422 | #elif defined(TCC_TARGET_C67) |
|
- | 1423 | case R_C60_GOT32: |
|
- | 1424 | case R_C60_GOTOFF: |
|
- | 1425 | case R_C60_GOTPC: |
|
- | 1426 | case R_C60_PLT32: |
|
- | 1427 | if (!s1->got) |
|
- | 1428 | build_got(s1); |
|
- | 1429 | if (type == R_C60_GOT32 || type == R_C60_PLT32) { |
|
- | 1430 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
- | 1431 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1432 | /* look at the symbol got offset. If none, then add one */ |
|
- | 1433 | if (type == R_C60_GOT32) |
|
- | 1434 | reloc_type = R_C60_GLOB_DAT; |
|
- | 1435 | else |
|
- | 1436 | reloc_type = R_C60_JMP_SLOT; |
|
- | 1437 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
|
- | 1438 | sym_index); |
|
- | 1439 | } |
|
- | 1440 | break; |
|
- | 1441 | #elif defined(TCC_TARGET_X86_64) |
|
- | 1442 | case R_X86_64_GOT32: |
|
- | 1443 | case R_X86_64_GOTTPOFF: |
|
- | 1444 | case R_X86_64_GOTPCREL: |
|
- | 1445 | case R_X86_64_GOTPCRELX: |
|
- | 1446 | case R_X86_64_REX_GOTPCRELX: |
|
- | 1447 | case R_X86_64_PLT32: |
|
- | 1448 | sym_index = ELFW(R_SYM)(rel->r_info); |
|
- | 1449 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1450 | if (type == R_X86_64_PLT32 && |
|
- | 1451 | ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) |
|
- | 1452 | { |
|
- | 1453 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); |
|
- | 1454 | break; |
|
- | 1455 | } |
|
- | 1456 | ||
- | 1457 | if (!s1->got) { |
|
- | 1458 | build_got(s1); |
|
- | 1459 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
860 | #elif defined(TCC_TARGET_C67) |
1460 | } |
861 | case R_C60_GOT32: |
1461 | if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || |
862 | case R_C60_GOTOFF: |
1462 | type == R_X86_64_GOTPCRELX || |
863 | case R_C60_GOTPC: |
1463 | type == R_X86_64_REX_GOTPCRELX || |
864 | case R_C60_PLT32: |
1464 | type == R_X86_64_PLT32) { |
865 | if (!s1->got) |
1465 | unsigned long ofs; |
866 | build_got(s1); |
1466 | /* look at the symbol got offset. If none, then add one */ |
867 | if (type == R_C60_GOT32 || type == R_C60_PLT32) { |
1467 | if (type == R_X86_64_PLT32) |
868 | sym_index = ELF32_R_SYM(rel->r_info); |
1468 | reloc_type = R_X86_64_JUMP_SLOT; |
Line 869... | Line 1469... | ||
869 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
1469 | else |
870 | /* look at the symbol got offset. If none, then add one */ |
1470 | reloc_type = R_X86_64_GLOB_DAT; |
871 | if (type == R_C60_GOT32) |
1471 | ofs = put_got_entry(s1, reloc_type, sym->st_size, |
872 | reloc_type = R_C60_GLOB_DAT; |
1472 | sym->st_info, sym_index); |
873 | else |
1473 | if (type == R_X86_64_PLT32) |
874 | reloc_type = R_C60_JMP_SLOT; |
1474 | /* We store the place of the generated PLT slot |
875 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
1475 | in our addend. */ |
Line 876... | Line 1476... | ||
876 | sym_index); |
1476 | rel->r_addend += ofs; |
877 | } |
1477 | } |
878 | break; |
1478 | break; |
879 | #else |
1479 | #else |
880 | #error unsupported CPU |
1480 | #error unsupported CPU |
881 | #endif |
1481 | #endif |
Line 914... | Line 1514... | ||
914 | memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); |
1514 | memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); |
915 | return symtab; |
1515 | return symtab; |
916 | } |
1516 | } |
Line 917... | Line 1517... | ||
917 | 1517 | ||
918 | /* put dynamic tag */ |
1518 | /* put dynamic tag */ |
919 | static void put_dt(Section *dynamic, int dt, unsigned long val) |
1519 | static void put_dt(Section *dynamic, int dt, addr_t val) |
920 | { |
1520 | { |
921 | Elf32_Dyn *dyn; |
1521 | ElfW(Dyn) *dyn; |
922 | dyn = section_ptr_add(dynamic, sizeof(Elf32_Dyn)); |
1522 | dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); |
923 | dyn->d_tag = dt; |
1523 | dyn->d_tag = dt; |
924 | dyn->d_un.d_val = val; |
1524 | dyn->d_un.d_val = val; |
Line 925... | Line 1525... | ||
925 | } |
1525 | } |
Line 942... | Line 1542... | ||
942 | end_offset = s->data_offset; |
1542 | end_offset = s->data_offset; |
943 | } |
1543 | } |
Line 944... | Line 1544... | ||
944 | 1544 | ||
945 | add_elf_sym(symtab_section, |
1545 | add_elf_sym(symtab_section, |
946 | 0, 0, |
1546 | 0, 0, |
947 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1547 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
948 | s->sh_num, sym_start); |
1548 | s->sh_num, sym_start); |
949 | add_elf_sym(symtab_section, |
1549 | add_elf_sym(symtab_section, |
950 | end_offset, 0, |
1550 | end_offset, 0, |
951 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1551 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
952 | s->sh_num, sym_end); |
1552 | s->sh_num, sym_end); |
Line 953... | Line -... | ||
953 | } |
- | |
954 | 1553 | } |
|
955 | /* add tcc runtime libraries */ |
1554 | |
956 | static void tcc_add_runtime(TCCState *s1) |
1555 | static int tcc_add_support(TCCState *s1, const char *filename) |
- | 1556 | { |
|
- | 1557 | char buf[1024]; |
|
- | 1558 | snprintf(buf, sizeof(buf), "%s/%s/%s", s1->tcc_lib_path, |
|
- | 1559 | /* an cpu specific path inside tcc_lib_path, mainly for keeping libtcc1.a */ |
|
- | 1560 | #ifdef TCC_TARGET_I386 |
|
- | 1561 | "i386" |
|
- | 1562 | #endif |
|
- | 1563 | #ifdef TCC_TARGET_X86_64 |
|
- | 1564 | "x86-64" |
|
- | 1565 | #endif |
|
- | 1566 | #ifdef TCC_TARGET_ARM |
|
- | 1567 | "arm" |
|
- | 1568 | #endif |
|
- | 1569 | #ifdef TCC_TARGET_ARM64 |
|
- | 1570 | "arm64" |
|
- | 1571 | #endif |
|
- | 1572 | #ifdef TCC_TARGET_C67 |
|
- | 1573 | "C67" |
|
- | 1574 | #endif |
|
- | 1575 | ,filename); |
|
- | 1576 | ||
Line -... | Line 1577... | ||
- | 1577 | return tcc_add_file(s1, buf, TCC_FILETYPE_BINARY); |
|
- | 1578 | } |
|
957 | { |
1579 | |
958 | char buf[1024]; |
- | |
959 | 1580 | ST_FUNC void tcc_add_bcheck(TCCState *s1) |
|
- | 1581 | { |
|
960 | #ifdef CONFIG_TCC_BCHECK |
1582 | #ifdef CONFIG_TCC_BCHECK |
961 | if (do_bounds_check) { |
- | |
962 | unsigned long *ptr; |
1583 | addr_t *ptr; |
Line 963... | Line 1584... | ||
963 | Section *init_section; |
1584 | |
964 | unsigned char *pinit; |
1585 | if (0 == s1->do_bounds_check) |
965 | int sym_index; |
1586 | return; |
966 | 1587 | ||
967 | /* XXX: add an object file to do that */ |
1588 | /* XXX: add an object file to do that */ |
968 | ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); |
1589 | ptr = section_ptr_add(bounds_section, sizeof(*ptr)); |
969 | *ptr = 0; |
- | |
970 | add_elf_sym(symtab_section, 0, 0, |
- | |
971 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
- | |
972 | bounds_section->sh_num, "__bounds_start"); |
- | |
973 | /* add bound check code */ |
1590 | *ptr = 0; |
974 | snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "bcheck.o"); |
1591 | add_elf_sym(symtab_section, 0, 0, |
- | 1592 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
|
- | 1593 | bounds_section->sh_num, "__bounds_start"); |
|
- | 1594 | if (s1->output_type != TCC_OUTPUT_MEMORY) { |
|
- | 1595 | /* add 'call __bound_init()' in .init section */ |
|
- | 1596 | ||
- | 1597 | /* XXX not called on MSYS, reason is unknown. For this |
|
- | 1598 | case a call to __bound_init is performed in bcheck.c |
|
- | 1599 | when __bound_ptr_add, __bound_new_region, |
|
975 | tcc_add_file(s1, buf); |
1600 | __bound_delete_region called */ |
976 | #ifdef TCC_TARGET_I386 |
1601 | |
977 | if (s1->output_type != TCC_OUTPUT_MEMORY) { |
1602 | int sym_index = find_elf_sym(symtab_section, "__bound_init"); |
978 | /* add 'call __bound_init()' in .init section */ |
1603 | if (sym_index) { |
979 | init_section = find_section(s1, ".init"); |
- | |
980 | pinit = section_ptr_add(init_section, 5); |
1604 | Section *init_section = find_section(s1, ".init"); |
981 | pinit[0] = 0xe8; |
1605 | unsigned char *pinit = section_ptr_add(init_section, 5); |
982 | put32(pinit + 1, -4); |
1606 | pinit[0] = 0xe8; |
983 | sym_index = find_elf_sym(symtab_section, "__bound_init"); |
1607 | write32le(pinit + 1, -4); |
- | 1608 | put_elf_reloc(symtab_section, init_section, |
|
984 | put_elf_reloc(symtab_section, init_section, |
1609 | init_section->data_offset - 4, R_386_PC32, sym_index); |
985 | init_section->data_offset - 4, R_386_PC32, sym_index); |
1610 | } |
- | 1611 | else |
|
- | 1612 | tcc_warning("__bound_init not defined"); |
|
- | 1613 | } |
|
- | 1614 | #endif |
|
- | 1615 | } |
|
- | 1616 | ||
- | 1617 | /* add tcc runtime libraries */ |
|
986 | } |
1618 | ST_FUNC void tcc_add_runtime(TCCState *s1) |
987 | #endif |
1619 | { |
988 | } |
1620 | tcc_add_pragma_libs(s1); |
989 | #endif |
- | |
- | 1621 | ||
- | 1622 | /* add libc */ |
|
990 | /* add libc */ |
1623 | if (!s1->nostdlib) { |
- | 1624 | tcc_add_library(s1, "c"); |
|
- | 1625 | #ifdef CONFIG_USE_LIBGCC |
|
- | 1626 | if (!s1->static_link) { |
|
991 | if (!s1->nostdlib) { |
1627 | tcc_add_file(s1, TCC_LIBGCC, TCC_FILETYPE_BINARY); |
- | 1628 | } |
|
992 | tcc_add_library(s1, "c"); |
1629 | #endif |
- | 1630 | #if !defined(TCC_TARGET_MEOS) |
|
- | 1631 | tcc_add_support(s1, "libtcc1.a"); |
|
- | 1632 | #endif |
|
- | 1633 | } |
|
- | 1634 | ||
- | 1635 | /* tcc_add_bcheck tries to relocate a call to __bound_init in _init so |
|
- | 1636 | libtcc1.a must be loaded before for __bound_init to be defined and |
|
993 | 1637 | crtn.o must be loaded after to not finalize _init too early. */ |
|
994 | snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a"); |
1638 | tcc_add_bcheck(s1); |
- | 1639 | ||
- | 1640 | if (!s1->nostdlib) { |
|
- | 1641 | /* add crt end if not memory output */ |
|
- | 1642 | if (s1->output_type != TCC_OUTPUT_MEMORY) |
|
995 | tcc_add_file(s1, buf); |
1643 | #if defined(TCC_TARGET_MEOS) |
- | 1644 | ; |
|
996 | } |
1645 | // tcc_add_crt(s1, "start.o"); |
997 | /* add crt end if not memory output */ |
1646 | #else |
Line 998... | Line 1647... | ||
998 | if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) { |
1647 | tcc_add_crt(s1, "crtn.o"); |
999 | tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o"); |
1648 | #endif |
1000 | } |
1649 | } |
1001 | } |
1650 | } |
1002 | 1651 | ||
1003 | /* add various standard linker symbols (must be done after the |
1652 | /* add various standard linker symbols (must be done after the |
1004 | sections are filled (for example after allocating common |
1653 | sections are filled (for example after allocating common |
1005 | symbols)) */ |
1654 | symbols)) */ |
Line 1006... | Line 1655... | ||
1006 | static void tcc_add_linker_symbols(TCCState *s1) |
1655 | ST_FUNC void tcc_add_linker_symbols(TCCState *s1) |
1007 | { |
1656 | { |
1008 | char buf[1024]; |
1657 | char buf[1024]; |
1009 | int i; |
1658 | int i; |
1010 | Section *s; |
1659 | Section *s; |
1011 | 1660 | ||
1012 | add_elf_sym(symtab_section, |
1661 | add_elf_sym(symtab_section, |
1013 | text_section->data_offset, 0, |
1662 | text_section->data_offset, 0, |
1014 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1663 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
1015 | text_section->sh_num, "_etext"); |
1664 | text_section->sh_num, "_etext"); |
1016 | add_elf_sym(symtab_section, |
1665 | add_elf_sym(symtab_section, |
1017 | data_section->data_offset, 0, |
1666 | data_section->data_offset, 0, |
1018 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1667 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
1019 | data_section->sh_num, "_edata"); |
1668 | data_section->sh_num, "_edata"); |
1020 | add_elf_sym(symtab_section, |
1669 | add_elf_sym(symtab_section, |
1021 | bss_section->data_offset, 0, |
1670 | bss_section->data_offset, 0, |
Line 1046... | Line 1695... | ||
1046 | p++; |
1695 | p++; |
1047 | } |
1696 | } |
1048 | snprintf(buf, sizeof(buf), "__start_%s", s->name); |
1697 | snprintf(buf, sizeof(buf), "__start_%s", s->name); |
1049 | add_elf_sym(symtab_section, |
1698 | add_elf_sym(symtab_section, |
1050 | 0, 0, |
1699 | 0, 0, |
1051 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1700 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
1052 | s->sh_num, buf); |
1701 | s->sh_num, buf); |
1053 | snprintf(buf, sizeof(buf), "__stop_%s", s->name); |
1702 | snprintf(buf, sizeof(buf), "__stop_%s", s->name); |
1054 | add_elf_sym(symtab_section, |
1703 | add_elf_sym(symtab_section, |
1055 | s->data_offset, 0, |
1704 | s->data_offset, 0, |
1056 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
1705 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
1057 | s->sh_num, buf); |
1706 | s->sh_num, buf); |
1058 | } |
1707 | } |
1059 | next_sec: ; |
1708 | next_sec: ; |
1060 | } |
1709 | } |
1061 | } |
1710 | } |
Line 1062... | Line -... | ||
1062 | - | ||
1063 | /* name of ELF interpreter */ |
- | |
1064 | #ifdef __FreeBSD__ |
- | |
1065 | static char elf_interp[] = "/usr/libexec/ld-elf.so.1"; |
- | |
1066 | #else |
- | |
1067 | static char elf_interp[] = "/lib/ld-linux.so.2"; |
- | |
1068 | #endif |
- | |
1069 | 1711 | ||
1070 | static void tcc_output_binary(TCCState *s1, FILE *f, |
1712 | static void tcc_output_binary(TCCState *s1, FILE *f, |
1071 | const int *section_order) |
1713 | const int *sec_order) |
1072 | { |
1714 | { |
1073 | Section *s; |
1715 | Section *s; |
Line 1074... | Line 1716... | ||
1074 | int i, offset, size; |
1716 | int i, offset, size; |
1075 | 1717 | ||
1076 | offset = 0; |
1718 | offset = 0; |
1077 | for(i=1;i |
1719 | for(i=1;i |
1078 | s = s1->sections[section_order[i]]; |
1720 | s = s1->sections[sec_order[i]]; |
1079 | if (s->sh_type != SHT_NOBITS && |
1721 | if (s->sh_type != SHT_NOBITS && |
1080 | (s->sh_flags & SHF_ALLOC)) { |
1722 | (s->sh_flags & SHF_ALLOC)) { |
1081 | while (offset < s->sh_offset) { |
1723 | while (offset < s->sh_offset) { |
Line 1087... | Line 1729... | ||
1087 | offset += size; |
1729 | offset += size; |
1088 | } |
1730 | } |
1089 | } |
1731 | } |
1090 | } |
1732 | } |
Line 1091... | Line -... | ||
1091 | - | ||
1092 | /* output an ELF file */ |
- | |
1093 | /* XXX: suppress unneeded sections */ |
1733 | |
1094 | int tcc_output_file(TCCState *s1, const char *filename) |
- | |
1095 | { |
- | |
1096 | Elf32_Ehdr ehdr; |
- | |
1097 | FILE *f; |
1734 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
1098 | int fd, mode, ret; |
- | |
1099 | int *section_order; |
- | |
1100 | int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k; |
- | |
1101 | unsigned long addr; |
- | |
1102 | Section *strsec, *s; |
- | |
1103 | Elf32_Shdr shdr, *sh; |
- | |
1104 | Elf32_Phdr *phdr, *ph; |
- | |
1105 | Section *interp, *dynamic, *dynstr; |
- | |
1106 | unsigned long saved_dynamic_data_offset; |
- | |
1107 | Elf32_Sym *sym; |
1735 | #define HAVE_PHDR 1 |
1108 | int type, file_type; |
- | |
Line -... | Line 1736... | ||
- | 1736 | #define EXTRA_RELITEMS 14 |
|
- | 1737 | ||
- | 1738 | /* move the relocation value from .dynsym to .got */ |
|
1109 | unsigned long rel_addr, rel_size; |
1739 | void patch_dynsym_undef(TCCState *s1, Section *s) |
1110 | 1740 | { |
|
Line -... | Line 1741... | ||
- | 1741 | uint32_t *gotd = (void *)s1->got->data; |
|
- | 1742 | ElfW(Sym) *sym; |
|
- | 1743 | ||
1111 | file_type = s1->output_type; |
1744 | gotd += 3; /* dummy entries in .got */ |
- | 1745 | /* relocate symbols in .dynsym */ |
|
1112 | s1->nb_errors = 0; |
1746 | for_each_elem(s, 1, sym, ElfW(Sym)) { |
1113 | 1747 | if (sym->st_shndx == SHN_UNDEF) { |
|
- | 1748 | *gotd++ = sym->st_value + 6; /* XXX 6 is magic ? */ |
|
- | 1749 | sym->st_value = 0; |
|
- | 1750 | } |
|
- | 1751 | } |
|
- | 1752 | } |
|
Line 1114... | Line -... | ||
1114 | if (file_type != TCC_OUTPUT_OBJ) { |
- | |
1115 | tcc_add_runtime(s1); |
- | |
1116 | } |
- | |
1117 | - | ||
1118 | phdr = NULL; |
1753 | #else |
1119 | section_order = NULL; |
1754 | #define HAVE_PHDR 1 |
1120 | interp = NULL; |
1755 | #define EXTRA_RELITEMS 9 |
1121 | dynamic = NULL; |
- | |
1122 | dynstr = NULL; /* avoid warning */ |
1756 | |
Line 1123... | Line 1757... | ||
1123 | saved_dynamic_data_offset = 0; /* avoid warning */ |
1757 | /* zero plt offsets of weak symbols in .dynsym */ |
- | 1758 | void patch_dynsym_undef(TCCState *s1, Section *s) |
|
- | 1759 | { |
|
- | 1760 | ElfW(Sym) *sym; |
|
- | 1761 | ||
Line 1124... | Line 1762... | ||
1124 | 1762 | for_each_elem(s, 1, sym, ElfW(Sym)) |
|
- | 1763 | if (sym->st_shndx == SHN_UNDEF && ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
|
1125 | if (file_type != TCC_OUTPUT_OBJ) { |
1764 | sym->st_value = 0; |
1126 | relocate_common_syms(); |
1765 | } |
1127 | 1766 | #endif |
|
Line 1128... | Line 1767... | ||
1128 | tcc_add_linker_symbols(s1); |
1767 | |
1129 | 1768 | ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) |
|
1130 | if (!s1->static_link) { |
1769 | { |
1131 | const char *name; |
1770 | int sym_index = ELFW(R_SYM) (rel->r_info); |
- | 1771 | ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
|
1132 | int sym_index, index; |
1772 | unsigned long offset; |
1133 | Elf32_Sym *esym, *sym_end; |
1773 | |
- | 1774 | if (sym_index >= s1->nb_sym_attrs) |
|
1134 | 1775 | return; |
|
1135 | if (file_type == TCC_OUTPUT_EXE) { |
1776 | offset = s1->sym_attrs[sym_index].got_offset; |
Line 1136... | Line 1777... | ||
1136 | char *ptr; |
1777 | section_reserve(s1->got, offset + PTR_SIZE); |
1137 | /* add interpreter section only if executable */ |
- | |
1138 | interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
- | |
1139 | interp->sh_addralign = 1; |
- | |
1140 | ptr = section_ptr_add(interp, sizeof(elf_interp)); |
1778 | #ifdef TCC_TARGET_X86_64 |
1141 | strcpy(ptr, elf_interp); |
1779 | /* only works for x86-64 */ |
1142 | } |
1780 | write32le(s1->got->data + offset + 4, sym->st_value >> 32); |
1143 | - | ||
1144 | /* add dynamic symbol table */ |
- | |
1145 | s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
1781 | #endif |
1146 | ".dynstr", |
1782 | write32le(s1->got->data + offset, sym->st_value & 0xffffffff); |
Line -... | Line 1783... | ||
- | 1783 | } |
|
- | 1784 | ||
- | 1785 | /* Perform relocation to GOT or PLT entries */ |
|
1147 | ".hash", SHF_ALLOC); |
1786 | ST_FUNC void fill_got(TCCState *s1) |
- | 1787 | { |
|
- | 1788 | Section *s; |
|
- | 1789 | ElfW_Rel *rel; |
|
- | 1790 | int i; |
|
1148 | dynstr = s1->dynsym->link; |
1791 | |
- | 1792 | for(i = 1; i < s1->nb_sections; i++) { |
|
- | 1793 | s = s1->sections[i]; |
|
- | 1794 | if (s->sh_type != SHT_RELX) |
|
- | 1795 | continue; |
|
- | 1796 | /* no need to handle got relocations */ |
|
1149 | 1797 | if (s->link != symtab_section) |
|
1150 | /* add dynamic section */ |
1798 | continue; |
- | 1799 | for_each_elem(s, 0, rel, ElfW_Rel) { |
|
- | 1800 | switch (ELFW(R_TYPE) (rel->r_info)) { |
|
- | 1801 | case R_X86_64_GOT32: |
|
- | 1802 | case R_X86_64_GOTPCREL: |
|
Line -... | Line 1803... | ||
- | 1803 | case R_X86_64_GOTPCRELX: |
|
- | 1804 | case R_X86_64_REX_GOTPCRELX: |
|
- | 1805 | case R_X86_64_PLT32: |
|
- | 1806 | fill_got_entry(s1, rel); |
|
- | 1807 | break; |
|
- | 1808 | } |
|
1151 | dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
1809 | } |
- | 1810 | } |
|
- | 1811 | } |
|
Line 1152... | Line 1812... | ||
1152 | SHF_ALLOC | SHF_WRITE); |
1812 | |
1153 | dynamic->link = dynstr; |
- | |
1154 | dynamic->sh_entsize = sizeof(Elf32_Dyn); |
1813 | /* Bind symbols of executable: resolve undefined symbols from exported symbols |
1155 | 1814 | in shared libraries and export non local defined symbols to shared libraries |
|
1156 | /* add PLT */ |
- | |
1157 | s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
- | |
1158 | SHF_ALLOC | SHF_EXECINSTR); |
1815 | if -rdynamic switch was given on command line */ |
1159 | s1->plt->sh_entsize = 4; |
- | |
1160 | - | ||
1161 | build_got(s1); |
- | |
1162 | 1816 | static void bind_exe_dynsyms(TCCState *s1) |
|
1163 | /* scan for undefined symbols and see if they are in the |
1817 | { |
1164 | dynamic symbols. If a symbol STT_FUNC is found, then we |
1818 | const char *name; |
1165 | add it in the PLT. If a symbol STT_OBJECT is found, we |
1819 | int sym_index, index; |
1166 | add it in the .bss section with a suitable relocation */ |
1820 | ElfW(Sym) *sym, *esym; |
1167 | sym_end = (Elf32_Sym *)(symtab_section->data + |
1821 | int type; |
1168 | symtab_section->data_offset); |
1822 | |
- | 1823 | /* Resolve undefined symbols from dynamic symbols. When there is a match: |
|
- | 1824 | - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT |
|
- | 1825 | - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ |
|
- | 1826 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
|
- | 1827 | if (sym->st_shndx == SHN_UNDEF) { |
|
- | 1828 | name = (char *) symtab_section->link->data + sym->st_name; |
|
- | 1829 | sym_index = find_elf_sym(s1->dynsymtab_section, name); |
|
1169 | if (file_type == TCC_OUTPUT_EXE) { |
1830 | if (sym_index) { |
1170 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
1831 | esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; |
1171 | sym < sym_end; |
1832 | type = ELFW(ST_TYPE)(esym->st_info); |
1172 | sym++) { |
1833 | if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { |
1173 | if (sym->st_shndx == SHN_UNDEF) { |
1834 | /* Indirect functions shall have STT_FUNC type in executable |
- | 1835 | * dynsym section. Indeed, a dlsym call following a lazy |
|
1174 | name = symtab_section->link->data + sym->st_name; |
1836 | * resolution would pick the symbol value from the |
1175 | sym_index = find_elf_sym(s1->dynsymtab_section, name); |
1837 | * executable dynsym entry which would contain the address |
1176 | if (sym_index) { |
1838 | * of the function wanted by the caller of dlsym instead of |
1177 | esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index]; |
1839 | * the address of the function that would return that |
- | 1840 | * address */ |
|
- | 1841 | put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
|
- | 1842 | ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), |
|
- | 1843 | sym - (ElfW(Sym) *)symtab_section->data); |
|
- | 1844 | } else if (type == STT_OBJECT) { |
|
- | 1845 | unsigned long offset; |
|
- | 1846 | ElfW(Sym) *dynsym; |
|
- | 1847 | offset = bss_section->data_offset; |
|
- | 1848 | /* XXX: which alignment ? */ |
|
- | 1849 | offset = (offset + 16 - 1) & -16; |
|
1178 | type = ELF32_ST_TYPE(esym->st_info); |
1850 | index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
1179 | if (type == STT_FUNC) { |
1851 | esym->st_info, 0, bss_section->sh_num, |
- | 1852 | name); |
|
- | 1853 | /* Ensure R_COPY works for weak symbol aliases */ |
|
- | 1854 | if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { |
|
- | 1855 | for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { |
|
1180 | put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
1856 | if ((dynsym->st_value == esym->st_value) |
1181 | esym->st_info, |
1857 | && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { |
1182 | sym - (Elf32_Sym *)symtab_section->data); |
1858 | char *dynname = (char *) s1->dynsymtab_section->link->data |
1183 | } else if (type == STT_OBJECT) { |
1859 | + dynsym->st_name; |
1184 | unsigned long offset; |
1860 | put_elf_sym(s1->dynsym, offset, dynsym->st_size, |
1185 | offset = bss_section->data_offset; |
1861 | dynsym->st_info, 0, |
1186 | /* XXX: which alignment ? */ |
1862 | bss_section->sh_num, dynname); |
1187 | offset = (offset + 16 - 1) & -16; |
1863 | break; |
1188 | index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
- | |
1189 | esym->st_info, 0, |
1864 | } |
1190 | bss_section->sh_num, name); |
1865 | } |
1191 | put_elf_reloc(s1->dynsym, bss_section, |
1866 | } |
1192 | offset, R_COPY, index); |
1867 | put_elf_reloc(s1->dynsym, bss_section, |
1193 | offset += esym->st_size; |
1868 | offset, R_COPY, index); |
1194 | bss_section->data_offset = offset; |
1869 | offset += esym->st_size; |
1195 | } |
- | |
1196 | } else { |
1870 | bss_section->data_offset = offset; |
1197 | /* STB_WEAK undefined symbols are accepted */ |
1871 | } |
1198 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
- | |
1199 | it */ |
1872 | } else { |
1200 | if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || |
1873 | /* STB_WEAK undefined symbols are accepted */ |
1201 | !strcmp(name, "_fp_hw")) { |
- | |
1202 | } else { |
1874 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ |
- | 1875 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || |
|
1203 | error_noabort("undefined symbol '%s'", name); |
1876 | !strcmp(name, "_fp_hw")) { |
1204 | } |
1877 | } else { |
Line -... | Line 1878... | ||
- | 1878 | tcc_error_noabort("undefined symbol '%s'", name); |
|
- | 1879 | } |
|
- | 1880 | } |
|
- | 1881 | } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
|
1205 | } |
1882 | /* if -rdynamic option, then export all non local symbols */ |
- | 1883 | name = (char *) symtab_section->link->data + sym->st_name; |
|
1206 | } else if (s1->rdynamic && |
1884 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, |
Line 1207... | Line 1885... | ||
1207 | ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
1885 | 0, sym->st_shndx, name); |
1208 | /* if -rdynamic option, then export all non |
1886 | } |
1209 | local symbols */ |
- | |
1210 | name = symtab_section->link->data + sym->st_name; |
- | |
1211 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1887 | } |
1212 | sym->st_info, 0, |
- | |
1213 | sym->st_shndx, name); |
- | |
1214 | } |
- | |
1215 | } |
1888 | } |
1216 | 1889 | ||
1217 | if (s1->nb_errors) |
1890 | /* Bind symbols of libraries: export non local symbols of executable that |
1218 | goto fail; |
1891 | resolve undefined symbols of shared libraries */ |
1219 | 1892 | static void bind_libs_dynsyms(TCCState *s1) |
|
1220 | /* now look at unresolved dynamic symbols and export |
1893 | { |
- | 1894 | const char *name; |
|
1221 | corresponding symbol */ |
1895 | int sym_index; |
1222 | sym_end = (Elf32_Sym *)(s1->dynsymtab_section->data + |
- | |
1223 | s1->dynsymtab_section->data_offset); |
1896 | ElfW(Sym) *sym, *esym; |
1224 | for(esym = (Elf32_Sym *)s1->dynsymtab_section->data + 1; |
- | |
1225 | esym < sym_end; |
1897 | |
1226 | esym++) { |
1898 | /* now look at unresolved dynamic symbols and export |
1227 | if (esym->st_shndx == SHN_UNDEF) { |
1899 | corresponding symbol */ |
1228 | name = s1->dynsymtab_section->link->data + esym->st_name; |
1900 | for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { |
1229 | sym_index = find_elf_sym(symtab_section, name); |
1901 | name = (char *) s1->dynsymtab_section->link->data + esym->st_name; |
1230 | if (sym_index) { |
1902 | sym_index = find_elf_sym(symtab_section, name); |
1231 | /* XXX: avoid adding a symbol if already |
1903 | if (sym_index) { |
- | 1904 | /* XXX: avoid adding a symbol if already present because of |
|
- | 1905 | -rdynamic ? */ |
|
- | 1906 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
|
- | 1907 | if (sym->st_shndx != SHN_UNDEF) |
|
1232 | present because of -rdynamic ? */ |
1908 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1233 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
1909 | sym->st_info, 0, sym->st_shndx, name); |
1234 | put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1910 | } else if (esym->st_shndx == SHN_UNDEF) { |
1235 | sym->st_info, 0, |
- | |
- | 1911 | /* weak symbols can stay undefined */ |
|
1236 | sym->st_shndx, name); |
1912 | if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) |
1237 | } else { |
1913 | tcc_warning("undefined dynamic symbol '%s'", name); |
1238 | if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { |
1914 | } |
1239 | /* weak symbols can stay undefined */ |
- | |
1240 | } else { |
- | |
1241 | warning("undefined dynamic symbol '%s'", name); |
1915 | } |
1242 | } |
1916 | } |
1243 | } |
1917 | |
1244 | } |
- | |
1245 | } |
1918 | /* Export all non local symbols (for shared libraries) */ |
1246 | } else { |
- | |
1247 | int nb_syms; |
1919 | static void export_global_syms(TCCState *s1) |
1248 | /* shared library case : we simply export all the global symbols */ |
1920 | { |
1249 | nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); |
1921 | int nb_syms, dynindex, index; |
1250 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
1922 | const char *name; |
1251 | for(sym = (Elf32_Sym *)symtab_section->data + 1; |
1923 | ElfW(Sym) *sym; |
Line -... | Line 1924... | ||
- | 1924 | ||
- | 1925 | nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym)); |
|
1252 | sym < sym_end; |
1926 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
- | 1927 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
|
- | 1928 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
|
Line 1253... | Line -... | ||
1253 | sym++) { |
- | |
1254 | if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
- | |
1255 | name = symtab_section->link->data + sym->st_name; |
- | |
1256 | index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1929 | name = (char *) symtab_section->link->data + sym->st_name; |
1257 | sym->st_info, 0, |
- | |
1258 | sym->st_shndx, name); |
1930 | dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1259 | s1->symtab_to_dynsym[sym - |
- | |
1260 | (Elf32_Sym *)symtab_section->data] = |
- | |
1261 | index; |
- | |
1262 | } |
- | |
Line -... | Line 1931... | ||
- | 1931 | sym->st_info, 0, sym->st_shndx, name); |
|
- | 1932 | index = sym - (ElfW(Sym) *) symtab_section->data; |
|
- | 1933 | s1->symtab_to_dynsym[index] = dynindex; |
|
- | 1934 | } |
|
- | 1935 | } |
|
- | 1936 | } |
|
- | 1937 | ||
- | 1938 | /* relocate the PLT: compute addresses and offsets in the PLT now that final |
|
1263 | } |
1939 | address for PLT and GOT are known (see fill_program_header) */ |
- | 1940 | ST_FUNC void relocate_plt(TCCState *s1) |
|
- | 1941 | { |
|
- | 1942 | uint8_t *p, *p_end; |
|
1264 | } |
1943 | |
1265 | 1944 | if (!s1->plt) |
|
- | 1945 | return; |
|
- | 1946 | ||
- | 1947 | p = s1->plt->data; |
|
- | 1948 | p_end = p + s1->plt->data_offset; |
|
- | 1949 | if (p < p_end) { |
|
- | 1950 | #if defined(TCC_TARGET_I386) |
|
- | 1951 | write32le(p + 2, read32le(p + 2) + s1->got->sh_addr); |
|
- | 1952 | write32le(p + 8, read32le(p + 8) + s1->got->sh_addr); |
|
- | 1953 | p += 16; |
|
1266 | build_got_entries(s1); |
1954 | while (p < p_end) { |
- | 1955 | write32le(p + 2, read32le(p + 2) + s1->got->sh_addr); |
|
1267 | 1956 | p += 16; |
|
- | 1957 | } |
|
- | 1958 | #elif defined(TCC_TARGET_X86_64) |
|
- | 1959 | int x = s1->got->sh_addr - s1->plt->sh_addr - 6; |
|
- | 1960 | write32le(p + 2, read32le(p + 2) + x); |
|
- | 1961 | write32le(p + 8, read32le(p + 8) + x - 6); |
|
- | 1962 | p += 16; |
|
- | 1963 | while (p < p_end) { |
|
- | 1964 | write32le(p + 2, read32le(p + 2) + x + s1->plt->data - p); |
|
- | 1965 | p += 16; |
|
- | 1966 | } |
|
- | 1967 | #elif defined(TCC_TARGET_ARM) |
|
- | 1968 | int x; |
|
- | 1969 | x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
|
- | 1970 | p += 16; |
|
- | 1971 | while (p < p_end) { |
|
- | 1972 | if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */ |
|
- | 1973 | p += 4; |
|
- | 1974 | write32le(p + 12, x + read32le(p + 12) + s1->plt->data - p); |
|
- | 1975 | p += 16; |
|
- | 1976 | } |
|
- | 1977 | #elif defined(TCC_TARGET_ARM64) |
|
- | 1978 | uint64_t plt = s1->plt->sh_addr; |
|
- | 1979 | uint64_t got = s1->got->sh_addr; |
|
- | 1980 | uint64_t off = (got >> 12) - (plt >> 12); |
|
1268 | /* add a list of needed dlls */ |
1981 | if ((off + ((uint32_t)1 << 20)) >> 21) |
- | 1982 | tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt); |
|
- | 1983 | write32le(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]! |
|
- | 1984 | write32le(p + 4, (0x90000010 | // adrp x16,... |
|
- | 1985 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
|
- | 1986 | write32le(p + 8, (0xf9400211 | // ldr x17,[x16,#...] |
|
- | 1987 | (got & 0xff8) << 7)); |
|
- | 1988 | write32le(p + 12, (0x91000210 | // add x16,x16,#... |
|
- | 1989 | (got & 0xfff) << 10)); |
|
- | 1990 | write32le(p + 16, 0xd61f0220); // br x17 |
|
- | 1991 | write32le(p + 20, 0xd503201f); // nop |
|
- | 1992 | write32le(p + 24, 0xd503201f); // nop |
|
- | 1993 | write32le(p + 28, 0xd503201f); // nop |
|
- | 1994 | p += 32; |
|
- | 1995 | while (p < p_end) { |
|
- | 1996 | uint64_t pc = plt + (p - s1->plt->data); |
|
- | 1997 | uint64_t addr = got + read64le(p); |
|
- | 1998 | uint64_t off = (addr >> 12) - (pc >> 12); |
|
1269 | for(i = 0; i < s1->nb_loaded_dlls; i++) { |
1999 | if ((off + ((uint32_t)1 << 20)) >> 21) |
1270 | DLLReference *dllref = s1->loaded_dlls[i]; |
2000 | tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc); |
Line 1271... | Line -... | ||
1271 | if (dllref->level == 0) |
- | |
1272 | put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
- | |
1273 | } |
- | |
1274 | /* XXX: currently, since we do not handle PIC code, we |
- | |
1275 | must relocate the readonly segments */ |
- | |
1276 | if (file_type == TCC_OUTPUT_DLL) |
- | |
1277 | put_dt(dynamic, DT_TEXTREL, 0); |
- | |
1278 | - | ||
1279 | /* add necessary space for other entries */ |
- | |
1280 | saved_dynamic_data_offset = dynamic->data_offset; |
2001 | write32le(p, (0x90000010 | // adrp x16,... |
1281 | dynamic->data_offset += 8 * 9; |
- | |
1282 | } else { |
- | |
1283 | /* still need to build got entries in case of static link */ |
2002 | (off & 0x1ffffc) << 3 | (off & 3) << 29)); |
Line 1284... | Line 2003... | ||
1284 | build_got_entries(s1); |
2003 | write32le(p + 4, (0xf9400211 | // ldr x17,[x16,#...] |
1285 | } |
- | |
1286 | } |
- | |
1287 | - | ||
1288 | memset(&ehdr, 0, sizeof(ehdr)); |
- | |
1289 | - | ||
1290 | /* we add a section for symbols */ |
- | |
1291 | strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
2004 | (addr & 0xff8) << 7)); |
1292 | put_elf_str(strsec, ""); |
- | |
1293 | 2005 | write32le(p + 8, (0x91000210 | // add x16,x16,#... |
|
1294 | /* compute number of sections */ |
- | |
1295 | shnum = s1->nb_sections; |
2006 | (addr & 0xfff) << 10)); |
1296 | - | ||
1297 | /* this array is used to reorder sections in the output file */ |
2007 | write32le(p + 12, 0xd61f0220); // br x17 |
1298 | section_order = tcc_malloc(sizeof(int) * shnum); |
- | |
1299 | section_order[0] = 0; |
- | |
Line 1300... | Line 2008... | ||
1300 | sh_order_index = 1; |
2008 | p += 16; |
1301 | - | ||
1302 | /* compute number of program headers */ |
- | |
1303 | switch(file_type) { |
- | |
1304 | default: |
2009 | } |
1305 | case TCC_OUTPUT_OBJ: |
2010 | #elif defined(TCC_TARGET_C67) |
1306 | phnum = 0; |
2011 | /* XXX: TODO */ |
1307 | break; |
2012 | #else |
1308 | case TCC_OUTPUT_EXE: |
2013 | #error unsupported CPU |
1309 | if (!s1->static_link) |
2014 | #endif |
1310 | phnum = 4; |
2015 | } |
1311 | else |
2016 | } |
- | 2017 | ||
- | 2018 | /* Allocate strings for section names and decide if an unallocated section |
|
1312 | phnum = 2; |
2019 | should be output. |
- | 2020 | ||
- | 2021 | NOTE: the strsec section comes last, so its size is also correct ! */ |
|
1313 | break; |
2022 | static void alloc_sec_names(TCCState *s1, int file_type, Section *strsec) |
1314 | case TCC_OUTPUT_DLL: |
2023 | { |
- | 2024 | int i; |
|
1315 | phnum = 3; |
2025 | Section *s; |
1316 | break; |
2026 | |
1317 | } |
2027 | /* Allocate strings for section names */ |
1318 | 2028 | for(i = 1; i < s1->nb_sections; i++) { |
|
1319 | /* allocate strings for section names and decide if an unallocated |
2029 | s = s1->sections[i]; |
1320 | section should be output */ |
2030 | s->sh_name = put_elf_str(strsec, s->name); |
- | 2031 | /* when generating a DLL, we include relocations but we may |
|
Line 1321... | Line 2032... | ||
1321 | /* NOTE: the strsec section comes last, so its size is also |
2032 | patch them */ |
- | 2033 | if (file_type == TCC_OUTPUT_DLL && |
|
- | 2034 | s->sh_type == SHT_RELX && |
|
- | 2035 | !(s->sh_flags & SHF_ALLOC)) { |
|
- | 2036 | /* gr: avoid bogus relocs for empty (debug) sections */ |
|
- | 2037 | if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) |
|
- | 2038 | prepare_dynamic_rel(s1, s); |
|
1322 | correct ! */ |
2039 | else if (s1->do_debug) |
- | 2040 | s->sh_size = s->data_offset; |
|
- | 2041 | } else if (s1->do_debug || |
|
- | 2042 | file_type == TCC_OUTPUT_OBJ || |
|
- | 2043 | file_type == TCC_OUTPUT_EXE || |
|
Line -... | Line 2044... | ||
- | 2044 | (s->sh_flags & SHF_ALLOC) || |
|
- | 2045 | i == (s1->nb_sections - 1)) { |
|
- | 2046 | /* we output all sections if debug or object file */ |
|
1323 | for(i = 1; i < s1->nb_sections; i++) { |
2047 | s->sh_size = s->data_offset; |
1324 | s = s1->sections[i]; |
2048 | } |
- | 2049 | } |
|
- | 2050 | } |
|
- | 2051 | ||
- | 2052 | /* Info to be copied in dynamic section */ |
|
- | 2053 | struct dyn_inf { |
|
- | 2054 | Section *dynamic; |
|
1325 | s->sh_name = put_elf_str(strsec, s->name); |
2055 | Section *dynstr; |
- | 2056 | unsigned long dyn_rel_off; |
|
- | 2057 | addr_t rel_addr; |
|
- | 2058 | addr_t rel_size; |
|
1326 | /* when generating a DLL, we include relocations but we may |
2059 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
- | 2060 | addr_t bss_addr; |
|
- | 2061 | addr_t bss_size; |
|
- | 2062 | #endif |
|
- | 2063 | }; |
|
- | 2064 | ||
1327 | patch them */ |
2065 | /* Assign sections to segments and decide how are sections laid out when loaded |
1328 | if (file_type == TCC_OUTPUT_DLL && |
2066 | in memory. This function also fills corresponding program headers. */ |
1329 | s->sh_type == SHT_REL && |
- | |
1330 | !(s->sh_flags & SHF_ALLOC)) { |
2067 | static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, |
1331 | prepare_dynamic_rel(s1, s); |
2068 | Section *interp, Section* strsec, |
1332 | } else if (do_debug || |
2069 | struct dyn_inf *dyninf, int *sec_order) |
1333 | file_type == TCC_OUTPUT_OBJ || |
2070 | { |
1334 | (s->sh_flags & SHF_ALLOC) || |
2071 | int i, j, k, file_type, sh_order_index, file_offset; |
1335 | i == (s1->nb_sections - 1)) { |
2072 | unsigned long s_align; |
1336 | /* we output all sections if debug or object file */ |
2073 | long long tmp; |
1337 | s->sh_size = s->data_offset; |
2074 | addr_t addr; |
1338 | } |
2075 | ElfW(Phdr) *ph; |
1339 | } |
2076 | Section *s; |
1340 | 2077 | ||
1341 | /* allocate program segment headers */ |
2078 | file_type = s1->output_type; |
1342 | phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr)); |
2079 | sh_order_index = 1; |
1343 | 2080 | file_offset = 0; |
|
1344 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
2081 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
1345 | file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); |
2082 | file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
1346 | } else { |
2083 | s_align = ELF_PAGE_SIZE; |
1347 | file_offset = 0; |
2084 | if (s1->section_align) |
Line 1348... | Line -... | ||
1348 | } |
- | |
1349 | if (phnum > 0) { |
- | |
1350 | /* compute section to program header mapping */ |
- | |
1351 | if (s1->has_text_addr) { |
- | |
1352 | int a_offset, p_offset; |
- | |
1353 | addr = s1->text_addr; |
2085 | s_align = s1->section_align; |
- | 2086 | ||
- | 2087 | if (phnum > 0) { |
|
- | 2088 | if (s1->has_text_addr) { |
|
1354 | /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
2089 | int a_offset, p_offset; |
1355 | ELF_PAGE_SIZE */ |
2090 | addr = s1->text_addr; |
- | 2091 | /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
|
- | 2092 | ELF_PAGE_SIZE */ |
|
- | 2093 | a_offset = (int) (addr & (s_align - 1)); |
|
- | 2094 | p_offset = file_offset & (s_align - 1); |
|
- | 2095 | if (a_offset < p_offset) |
|
- | 2096 | a_offset += s_align; |
|
Line 1356... | Line 2097... | ||
1356 | a_offset = addr & (ELF_PAGE_SIZE - 1); |
2097 | file_offset += (a_offset - p_offset); |
1357 | p_offset = file_offset & (ELF_PAGE_SIZE - 1); |
2098 | } else { |
1358 | if (a_offset < p_offset) |
2099 | if (file_type == TCC_OUTPUT_DLL) |
1359 | a_offset += ELF_PAGE_SIZE; |
2100 | addr = 0; |
1360 | file_offset += (a_offset - p_offset); |
2101 | else |
1361 | } else { |
2102 | addr = ELF_START_ADDR; |
1362 | if (file_type == TCC_OUTPUT_DLL) |
2103 | /* compute address after headers */ |
Line -... | Line 2104... | ||
- | 2104 | addr += (file_offset & (s_align - 1)); |
|
- | 2105 | } |
|
1363 | addr = 0; |
2106 | |
1364 | else |
2107 | ph = &phdr[0]; |
1365 | addr = ELF_START_ADDR; |
2108 | /* Leave one program headers for the program interpreter and one for |
1366 | /* compute address after headers */ |
2109 | the program header table itself if needed. These are done later as |
1367 | addr += (file_offset & (ELF_PAGE_SIZE - 1)); |
2110 | they require section layout to be done first. */ |
1368 | } |
2111 | if (interp) |
1369 | 2112 | ph += 1 + HAVE_PHDR; |
|
Line 1406... | Line 2149... | ||
1406 | } else if (s->sh_type == SHT_DYNSYM || |
2149 | } else if (s->sh_type == SHT_DYNSYM || |
1407 | s->sh_type == SHT_STRTAB || |
2150 | s->sh_type == SHT_STRTAB || |
1408 | s->sh_type == SHT_HASH) { |
2151 | s->sh_type == SHT_HASH) { |
1409 | if (k != 1) |
2152 | if (k != 1) |
1410 | continue; |
2153 | continue; |
1411 | } else if (s->sh_type == SHT_REL) { |
2154 | } else if (s->sh_type == SHT_RELX) { |
1412 | if (k != 2) |
2155 | if (k != 2) |
1413 | continue; |
2156 | continue; |
1414 | } else if (s->sh_type == SHT_NOBITS) { |
2157 | } else if (s->sh_type == SHT_NOBITS) { |
1415 | if (k != 4) |
2158 | if (k != 4) |
1416 | continue; |
2159 | continue; |
1417 | } else { |
2160 | } else { |
1418 | if (k != 3) |
2161 | if (k != 3) |
1419 | continue; |
2162 | continue; |
1420 | } |
2163 | } |
1421 | section_order[sh_order_index++] = i; |
2164 | sec_order[sh_order_index++] = i; |
Line 1422... | Line 2165... | ||
1422 | 2165 | ||
1423 | /* section matches: we align it and add its size */ |
2166 | /* section matches: we align it and add its size */ |
1424 | tmp = addr; |
2167 | tmp = addr; |
1425 | addr = (addr + s->sh_addralign - 1) & |
2168 | addr = (addr + s->sh_addralign - 1) & |
1426 | ~(s->sh_addralign - 1); |
2169 | ~(s->sh_addralign - 1); |
1427 | file_offset += addr - tmp; |
2170 | file_offset += (int) ( addr - tmp ); |
1428 | s->sh_offset = file_offset; |
2171 | s->sh_offset = file_offset; |
Line 1429... | Line 2172... | ||
1429 | s->sh_addr = addr; |
2172 | s->sh_addr = addr; |
1430 | 2173 | ||
1431 | /* update program header infos */ |
2174 | /* update program header infos */ |
1432 | if (ph->p_offset == 0) { |
2175 | if (ph->p_offset == 0) { |
1433 | ph->p_offset = file_offset; |
2176 | ph->p_offset = file_offset; |
1434 | ph->p_vaddr = addr; |
2177 | ph->p_vaddr = addr; |
1435 | ph->p_paddr = ph->p_vaddr; |
2178 | ph->p_paddr = ph->p_vaddr; |
1436 | } |
2179 | } |
- | 2180 | /* update dynamic relocation infos */ |
|
- | 2181 | if (s->sh_type == SHT_RELX) { |
|
- | 2182 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
|
- | 2183 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { |
|
- | 2184 | dyninf->rel_addr = addr; |
|
- | 2185 | dyninf->rel_size += s->sh_size; /* XXX only first rel. */ |
|
- | 2186 | } |
|
- | 2187 | if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { |
|
- | 2188 | dyninf->bss_addr = addr; |
|
- | 2189 | dyninf->bss_size = s->sh_size; /* XXX only first rel. */ |
|
1437 | /* update dynamic relocation infos */ |
2190 | } |
1438 | if (s->sh_type == SHT_REL) { |
2191 | #else |
1439 | if (rel_size == 0) |
2192 | if (dyninf->rel_size == 0) |
- | 2193 | dyninf->rel_addr = addr; |
|
1440 | rel_addr = addr; |
2194 | dyninf->rel_size += s->sh_size; |
1441 | rel_size += s->sh_size; |
2195 | #endif |
1442 | } |
2196 | } |
1443 | addr += s->sh_size; |
2197 | addr += s->sh_size; |
1444 | if (s->sh_type != SHT_NOBITS) |
2198 | if (s->sh_type != SHT_NOBITS) |
1445 | file_offset += s->sh_size; |
2199 | file_offset += s->sh_size; |
- | 2200 | } |
|
- | 2201 | } |
|
- | 2202 | if (j == 0) { |
|
- | 2203 | /* Make the first PT_LOAD segment include the program |
|
- | 2204 | headers itself (and the ELF header as well), it'll |
|
- | 2205 | come out with same memory use but will make various |
|
- | 2206 | tools like binutils strip work better. */ |
|
- | 2207 | ph->p_offset &= ~(ph->p_align - 1); |
|
- | 2208 | ph->p_vaddr &= ~(ph->p_align - 1); |
|
1446 | } |
2209 | ph->p_paddr &= ~(ph->p_align - 1); |
1447 | } |
2210 | } |
1448 | ph->p_filesz = file_offset - ph->p_offset; |
2211 | ph->p_filesz = file_offset - ph->p_offset; |
1449 | ph->p_memsz = addr - ph->p_vaddr; |
2212 | ph->p_memsz = addr - ph->p_vaddr; |
1450 | ph++; |
2213 | ph++; |
1451 | if (j == 0) { |
2214 | if (j == 0) { |
1452 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
2215 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
1453 | /* if in the middle of a page, we duplicate the page in |
2216 | /* if in the middle of a page, we duplicate the page in |
1454 | memory so that one copy is RX and the other is RW */ |
2217 | memory so that one copy is RX and the other is RW */ |
1455 | if ((addr & (ELF_PAGE_SIZE - 1)) != 0) |
2218 | if ((addr & (s_align - 1)) != 0) |
1456 | addr += ELF_PAGE_SIZE; |
2219 | addr += s_align; |
1457 | } else { |
2220 | } else { |
1458 | addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); |
2221 | addr = (addr + s_align - 1) & ~(s_align - 1); |
1459 | file_offset = (file_offset + ELF_PAGE_SIZE - 1) & |
2222 | file_offset = (file_offset + s_align - 1) & ~(s_align - 1); |
1460 | ~(ELF_PAGE_SIZE - 1); |
2223 | } |
1461 | } |
2224 | } |
Line -... | Line 2225... | ||
- | 2225 | } |
|
- | 2226 | } |
|
- | 2227 | ||
- | 2228 | /* all other sections come after */ |
|
- | 2229 | for(i = 1; i < s1->nb_sections; i++) { |
|
- | 2230 | s = s1->sections[i]; |
|
- | 2231 | if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
|
- | 2232 | continue; |
|
- | 2233 | sec_order[sh_order_index++] = i; |
|
- | 2234 | ||
- | 2235 | file_offset = (file_offset + s->sh_addralign - 1) & |
|
- | 2236 | ~(s->sh_addralign - 1); |
|
- | 2237 | s->sh_offset = file_offset; |
|
- | 2238 | if (s->sh_type != SHT_NOBITS) |
|
- | 2239 | file_offset += s->sh_size; |
|
- | 2240 | } |
|
- | 2241 | ||
- | 2242 | return file_offset; |
|
- | 2243 | } |
|
- | 2244 | ||
- | 2245 | static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, |
|
- | 2246 | Section *dynamic) |
|
1462 | } |
2247 | { |
1463 | } |
2248 | ElfW(Phdr) *ph; |
1464 | 2249 | ||
Line -... | Line 2250... | ||
- | 2250 | /* if interpreter, then add corresponding program header */ |
|
- | 2251 | if (interp) { |
|
- | 2252 | ph = &phdr[0]; |
|
- | 2253 | ||
- | 2254 | if (HAVE_PHDR) |
|
- | 2255 | { |
|
- | 2256 | int len = phnum * sizeof(ElfW(Phdr)); |
|
- | 2257 | ||
- | 2258 | ph->p_type = PT_PHDR; |
|
- | 2259 | ph->p_offset = sizeof(ElfW(Ehdr)); |
|
- | 2260 | ph->p_vaddr = interp->sh_addr - len; |
|
- | 2261 | ph->p_paddr = ph->p_vaddr; |
|
- | 2262 | ph->p_filesz = ph->p_memsz = len; |
|
- | 2263 | ph->p_flags = PF_R | PF_X; |
|
1465 | /* if interpreter, then add corresponing program header */ |
2264 | ph->p_align = 4; /* interp->sh_addralign; */ |
1466 | if (interp) { |
2265 | ph++; |
1467 | ph = &phdr[0]; |
2266 | } |
1468 | 2267 | ||
1469 | ph->p_type = PT_INTERP; |
2268 | ph->p_type = PT_INTERP; |
1470 | ph->p_offset = interp->sh_offset; |
2269 | ph->p_offset = interp->sh_offset; |
1471 | ph->p_vaddr = interp->sh_addr; |
2270 | ph->p_vaddr = interp->sh_addr; |
1472 | ph->p_paddr = ph->p_vaddr; |
2271 | ph->p_paddr = ph->p_vaddr; |
1473 | ph->p_filesz = interp->sh_size; |
2272 | ph->p_filesz = interp->sh_size; |
Line 1474... | Line 2273... | ||
1474 | ph->p_memsz = interp->sh_size; |
2273 | ph->p_memsz = interp->sh_size; |
1475 | ph->p_flags = PF_R; |
2274 | ph->p_flags = PF_R; |
1476 | ph->p_align = interp->sh_addralign; |
- | |
1477 | } |
- | |
1478 | 2275 | ph->p_align = interp->sh_addralign; |
|
Line 1479... | Line 2276... | ||
1479 | /* if dynamic section, then add corresponing program header */ |
2276 | } |
1480 | if (dynamic) { |
2277 | |
1481 | Elf32_Sym *sym_end; |
2278 | /* if dynamic section, then add corresponding program header */ |
1482 | 2279 | if (dynamic) { |
|
1483 | ph = &phdr[phnum - 1]; |
2280 | ph = &phdr[phnum - 1]; |
1484 | 2281 | ||
1485 | ph->p_type = PT_DYNAMIC; |
2282 | ph->p_type = PT_DYNAMIC; |
1486 | ph->p_offset = dynamic->sh_offset; |
2283 | ph->p_offset = dynamic->sh_offset; |
1487 | ph->p_vaddr = dynamic->sh_addr; |
- | |
1488 | ph->p_paddr = ph->p_vaddr; |
- | |
1489 | ph->p_filesz = dynamic->sh_size; |
- | |
1490 | ph->p_memsz = dynamic->sh_size; |
- | |
1491 | ph->p_flags = PF_R | PF_W; |
- | |
1492 | ph->p_align = dynamic->sh_addralign; |
- | |
1493 | - | ||
1494 | /* put GOT dynamic section address */ |
- | |
1495 | put32(s1->got->data, dynamic->sh_addr); |
- | |
1496 | - | ||
1497 | /* relocate the PLT */ |
- | |
1498 | if (file_type == TCC_OUTPUT_EXE) { |
- | |
1499 | uint8_t *p, *p_end; |
- | |
1500 | - | ||
1501 | p = s1->plt->data; |
- | |
1502 | p_end = p + s1->plt->data_offset; |
- | |
1503 | if (p < p_end) { |
- | |
1504 | #if defined(TCC_TARGET_I386) |
- | |
1505 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
- | |
1506 | put32(p + 8, get32(p + 8) + s1->got->sh_addr); |
- | |
1507 | p += 16; |
- | |
1508 | while (p < p_end) { |
- | |
1509 | put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
- | |
1510 | p += 16; |
- | |
1511 | } |
- | |
1512 | #elif defined(TCC_TARGET_ARM) |
- | |
1513 | int x; |
- | |
1514 | x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
- | |
1515 | p +=16; |
- | |
1516 | while (p < p_end) { |
- | |
1517 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
- | |
1518 | p += 16; |
- | |
1519 | } |
2284 | ph->p_vaddr = dynamic->sh_addr; |
1520 | #elif defined(TCC_TARGET_C67) |
2285 | ph->p_paddr = ph->p_vaddr; |
Line 1521... | Line -... | ||
1521 | /* XXX: TODO */ |
- | |
1522 | #else |
2286 | ph->p_filesz = dynamic->sh_size; |
1523 | #error unsupported CPU |
- | |
1524 | #endif |
- | |
1525 | } |
2287 | ph->p_memsz = dynamic->sh_size; |
1526 | } |
- | |
1527 | 2288 | ph->p_flags = PF_R | PF_W; |
|
1528 | /* relocate symbols in .dynsym */ |
- | |
1529 | sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); |
- | |
1530 | for(sym = (Elf32_Sym *)s1->dynsym->data + 1; |
- | |
1531 | sym < sym_end; |
- | |
1532 | sym++) { |
- | |
1533 | if (sym->st_shndx == SHN_UNDEF) { |
- | |
- | 2289 | ph->p_align = dynamic->sh_addralign; |
|
1534 | /* relocate to the PLT if the symbol corresponds |
2290 | } |
- | 2291 | } |
|
1535 | to a PLT entry */ |
2292 | |
Line 1536... | Line 2293... | ||
1536 | if (sym->st_value) |
2293 | /* Fill the dynamic section with tags describing the address and size of |
1537 | sym->st_value += s1->plt->sh_addr; |
2294 | sections */ |
1538 | } else if (sym->st_shndx < SHN_LORESERVE) { |
2295 | static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) |
1539 | /* do symbol relocation */ |
2296 | { |
1540 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
2297 | Section *dynamic; |
1541 | } |
2298 | |
1542 | } |
2299 | dynamic = dyninf->dynamic; |
- | 2300 | ||
- | 2301 | /* put dynamic section entries */ |
|
- | 2302 | dynamic->data_offset = dyninf->dyn_rel_off; |
|
- | 2303 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
|
- | 2304 | put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); |
|
- | 2305 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
|
- | 2306 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
|
- | 2307 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
|
- | 2308 | #if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) |
|
- | 2309 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
|
- | 2310 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
|
- | 2311 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
|
- | 2312 | #else |
|
1543 | 2313 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
|
1544 | /* put dynamic section entries */ |
2314 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
1545 | dynamic->data_offset = saved_dynamic_data_offset; |
2315 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); |
- | 2316 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); |
|
- | 2317 | put_dt(dynamic, DT_PLTREL, DT_REL); |
|
- | 2318 | put_dt(dynamic, DT_REL, dyninf->bss_addr); |
|
- | 2319 | put_dt(dynamic, DT_RELSZ, dyninf->bss_size); |
|
1546 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
2320 | #else |
1547 | put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); |
2321 | put_dt(dynamic, DT_REL, dyninf->rel_addr); |
Line 1548... | Line 2322... | ||
1548 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
2322 | put_dt(dynamic, DT_RELSZ, dyninf->rel_size); |
1549 | put_dt(dynamic, DT_STRSZ, dynstr->data_offset); |
2323 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
1550 | put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); |
2324 | #endif |
1551 | put_dt(dynamic, DT_REL, rel_addr); |
- | |
1552 | put_dt(dynamic, DT_RELSZ, rel_size); |
2325 | #endif |
1553 | put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); |
- | |
1554 | put_dt(dynamic, DT_NULL, 0); |
- | |
1555 | } |
2326 | if (s1->do_debug) |
1556 | - | ||
1557 | ehdr.e_phentsize = sizeof(Elf32_Phdr); |
2327 | put_dt(dynamic, DT_DEBUG, 0); |
1558 | ehdr.e_phnum = phnum; |
- | |
1559 | ehdr.e_phoff = sizeof(Elf32_Ehdr); |
- | |
1560 | } |
- | |
1561 | - | ||
1562 | /* all other sections come after */ |
- | |
1563 | for(i = 1; i < s1->nb_sections; i++) { |
- | |
1564 | s = s1->sections[i]; |
- | |
1565 | if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
- | |
Line 1566... | Line -... | ||
1566 | continue; |
- | |
1567 | section_order[sh_order_index++] = i; |
- | |
1568 | - | ||
1569 | file_offset = (file_offset + s->sh_addralign - 1) & |
2328 | put_dt(dynamic, DT_NULL, 0); |
Line 1570... | Line 2329... | ||
1570 | ~(s->sh_addralign - 1); |
2329 | } |
1571 | s->sh_offset = file_offset; |
- | |
1572 | if (s->sh_type != SHT_NOBITS) |
2330 | |
1573 | file_offset += s->sh_size; |
- | |
1574 | } |
- | |
Line 1575... | Line 2331... | ||
1575 | 2331 | /* Relocate remaining sections and symbols (that is those not related to |
|
1576 | /* if building executable or DLL, then relocate each section |
2332 | dynamic linking) */ |
1577 | except the GOT which is already relocated */ |
2333 | static int final_sections_reloc(TCCState *s1) |
1578 | if (file_type != TCC_OUTPUT_OBJ) { |
2334 | { |
- | 2335 | int i; |
|
- | 2336 | Section *s; |
|
- | 2337 | ||
- | 2338 | relocate_syms(s1, 0); |
|
- | 2339 | ||
1579 | relocate_syms(s1, 0); |
2340 | if (s1->nb_errors != 0) |
- | 2341 | return -1; |
|
- | 2342 | ||
1580 | 2343 | /* relocate sections */ |
|
1581 | if (s1->nb_errors != 0) { |
2344 | /* XXX: ignore sections with allocated relocations ? */ |
Line 1582... | Line 2345... | ||
1582 | fail: |
2345 | for(i = 1; i < s1->nb_sections; i++) { |
1583 | ret = -1; |
2346 | s = s1->sections[i]; |
1584 | goto the_end; |
2347 | #ifdef TCC_TARGET_I386 |
1585 | } |
2348 | if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr |
1586 | 2349 | /* On X86 gdb 7.3 works in any case but gdb 6.6 will crash if SHF_ALLOC |
|
1587 | /* relocate sections */ |
2350 | checking is removed */ |
1588 | /* XXX: ignore sections with allocated relocations ? */ |
2351 | #else |
1589 | for(i = 1; i < s1->nb_sections; i++) { |
2352 | if (s->reloc && s != s1->got) |
1590 | s = s1->sections[i]; |
2353 | /* On X86_64 gdb 7.3 will crash if SHF_ALLOC checking is present */ |
1591 | if (s->reloc && s != s1->got) |
- | |
1592 | relocate_section(s1, s); |
- | |
1593 | } |
- | |
1594 | - | ||
1595 | /* relocate relocation entries if the relocation tables are |
2354 | #endif |
1596 | allocated in the executable */ |
- | |
1597 | for(i = 1; i < s1->nb_sections; i++) { |
2355 | relocate_section(s1, s); |
Line 1598... | Line 2356... | ||
1598 | s = s1->sections[i]; |
2356 | } |
1599 | if ((s->sh_flags & SHF_ALLOC) && |
2357 | |
1600 | s->sh_type == SHT_REL) { |
- | |
1601 | relocate_rel(s1, s); |
- | |
1602 | } |
2358 | /* relocate relocation entries if the relocation tables are |
1603 | } |
2359 | allocated in the executable */ |
1604 | 2360 | for(i = 1; i < s1->nb_sections; i++) { |
|
1605 | /* get entry point address */ |
2361 | s = s1->sections[i]; |
1606 | if (file_type == TCC_OUTPUT_EXE) |
2362 | if ((s->sh_flags & SHF_ALLOC) && |
1607 | ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start"); |
2363 | s->sh_type == SHT_RELX) { |
1608 | else |
2364 | relocate_rel(s1, s); |
Line 1609... | Line 2365... | ||
1609 | ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
2365 | } |
1610 | } |
2366 | } |
- | 2367 | return 0; |
|
1611 | 2368 | } |
|
- | 2369 | ||
1612 | /* write elf file */ |
2370 | /* Create an ELF file on disk. |
1613 | if (file_type == TCC_OUTPUT_OBJ) |
- | |
1614 | mode = 0666; |
2371 | This function handle ELF specific layout requirements */ |
- | 2372 | static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, |
|
1615 | else |
2373 | int file_offset, int *sec_order) |
- | 2374 | { |
|
Line 1616... | Line 2375... | ||
1616 | mode = 0777; |
2375 | int i, shnum, offset, size, file_type; |
1617 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
2376 | Section *s; |
Line 1618... | Line 2377... | ||
1618 | if (fd < 0) { |
2377 | ElfW(Ehdr) ehdr; |
1619 | error_noabort("could not write '%s'", filename); |
2378 | ElfW(Shdr) shdr, *sh; |
1620 | goto fail; |
2379 | |
1621 | } |
2380 | file_type = s1->output_type; |
1622 | f = fdopen(fd, "wb"); |
2381 | shnum = s1->nb_sections; |
1623 | 2382 | ||
1624 | #ifdef TCC_TARGET_COFF |
2383 | memset(&ehdr, 0, sizeof(ehdr)); |
1625 | if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { |
2384 | |
1626 | tcc_output_coff(s1, f); |
2385 | if (phnum > 0) { |
1627 | } else |
2386 | ehdr.e_phentsize = sizeof(ElfW(Phdr)); |
1628 | #endif |
2387 | ehdr.e_phnum = phnum; |
1629 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
2388 | ehdr.e_phoff = sizeof(ElfW(Ehdr)); |
- | 2389 | } |
|
- | 2390 | ||
- | 2391 | /* align to 4 */ |
|
- | 2392 | file_offset = (file_offset + 3) & -4; |
|
- | 2393 | ||
- | 2394 | /* fill header */ |
|
- | 2395 | ehdr.e_ident[0] = ELFMAG0; |
|
- | 2396 | ehdr.e_ident[1] = ELFMAG1; |
|
- | 2397 | ehdr.e_ident[2] = ELFMAG2; |
|
- | 2398 | ehdr.e_ident[3] = ELFMAG3; |
|
1630 | sort_syms(s1, symtab_section); |
2399 | ehdr.e_ident[4] = ELFCLASSW; |
1631 | 2400 | ehdr.e_ident[5] = ELFDATA2LSB; |
|
- | 2401 | ehdr.e_ident[6] = EV_CURRENT; |
|
1632 | /* align to 4 */ |
2402 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
1633 | file_offset = (file_offset + 3) & -4; |
2403 | ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
1634 | 2404 | #endif |
|
1635 | /* fill header */ |
2405 | #ifdef TCC_TARGET_ARM |
- | 2406 | #ifdef TCC_ARM_EABI |
|
1636 | ehdr.e_ident[0] = ELFMAG0; |
2407 | ehdr.e_ident[EI_OSABI] = 0; |
1637 | ehdr.e_ident[1] = ELFMAG1; |
2408 | ehdr.e_flags = EF_ARM_EABI_VER4; |
1638 | ehdr.e_ident[2] = ELFMAG2; |
2409 | if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) |
- | 2410 | ehdr.e_flags |= EF_ARM_HASENTRY; |
|
1639 | ehdr.e_ident[3] = ELFMAG3; |
2411 | if (s1->float_abi == ARM_HARD_FLOAT) |
1640 | ehdr.e_ident[4] = ELFCLASS32; |
2412 | ehdr.e_flags |= EF_ARM_VFP_FLOAT; |
1641 | ehdr.e_ident[5] = ELFDATA2LSB; |
2413 | else |
1642 | ehdr.e_ident[6] = EV_CURRENT; |
2414 | ehdr.e_flags |= EF_ARM_SOFT_FLOAT; |
1643 | #ifdef __FreeBSD__ |
2415 | #else |
1644 | ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
2416 | ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
1645 | #endif |
2417 | #endif |
1646 | #ifdef TCC_TARGET_ARM |
2418 | #endif |
1647 | ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
2419 | switch(file_type) { |
1648 | #endif |
2420 | default: |
1649 | switch(file_type) { |
2421 | case TCC_OUTPUT_EXE: |
1650 | default: |
2422 | ehdr.e_type = ET_EXEC; |
Line 1651... | Line 2423... | ||
1651 | case TCC_OUTPUT_EXE: |
2423 | ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1); |
1652 | ehdr.e_type = ET_EXEC; |
2424 | break; |
1653 | break; |
2425 | case TCC_OUTPUT_DLL: |
Line -... | Line 2426... | ||
- | 2426 | ehdr.e_type = ET_DYN; |
|
1654 | case TCC_OUTPUT_DLL: |
2427 | ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
1655 | ehdr.e_type = ET_DYN; |
2428 | break; |
1656 | break; |
2429 | case TCC_OUTPUT_OBJ: |
- | 2430 | ehdr.e_type = ET_REL; |
|
- | 2431 | break; |
|
1657 | case TCC_OUTPUT_OBJ: |
2432 | } |
1658 | ehdr.e_type = ET_REL; |
2433 | ehdr.e_machine = EM_TCC_TARGET; |
1659 | break; |
2434 | ehdr.e_version = EV_CURRENT; |
1660 | } |
2435 | ehdr.e_shoff = file_offset; |
1661 | ehdr.e_machine = EM_TCC_TARGET; |
2436 | ehdr.e_ehsize = sizeof(ElfW(Ehdr)); |
- | 2437 | ehdr.e_shentsize = sizeof(ElfW(Shdr)); |
|
1662 | ehdr.e_version = EV_CURRENT; |
2438 | ehdr.e_shnum = shnum; |
1663 | ehdr.e_shoff = file_offset; |
2439 | ehdr.e_shstrndx = shnum - 1; |
1664 | ehdr.e_ehsize = sizeof(Elf32_Ehdr); |
2440 | |
1665 | ehdr.e_shentsize = sizeof(Elf32_Shdr); |
2441 | fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); |
Line 1689... | Line 2465... | ||
1689 | offset++; |
2465 | offset++; |
1690 | } |
2466 | } |
Line 1691... | Line 2467... | ||
1691 | 2467 | ||
1692 | for(i=0;i |
2468 | for(i = 0; i < s1->nb_sections; i++) { |
1693 | sh = &shdr; |
2469 | sh = &shdr; |
1694 | memset(sh, 0, sizeof(Elf32_Shdr)); |
2470 | memset(sh, 0, sizeof(ElfW(Shdr))); |
1695 | s = s1->sections[i]; |
2471 | s = s1->sections[i]; |
1696 | if (s) { |
2472 | if (s) { |
1697 | sh->sh_name = s->sh_name; |
2473 | sh->sh_name = s->sh_name; |
1698 | sh->sh_type = s->sh_type; |
2474 | sh->sh_type = s->sh_type; |
Line 1704... | Line 2480... | ||
1704 | sh->sh_addralign = s->sh_addralign; |
2480 | sh->sh_addralign = s->sh_addralign; |
1705 | sh->sh_addr = s->sh_addr; |
2481 | sh->sh_addr = s->sh_addr; |
1706 | sh->sh_offset = s->sh_offset; |
2482 | sh->sh_offset = s->sh_offset; |
1707 | sh->sh_size = s->sh_size; |
2483 | sh->sh_size = s->sh_size; |
1708 | } |
2484 | } |
1709 | fwrite(sh, 1, sizeof(Elf32_Shdr), f); |
2485 | fwrite(sh, 1, sizeof(ElfW(Shdr)), f); |
1710 | } |
2486 | } |
1711 | } else { |
- | |
1712 | tcc_output_binary(s1, f, section_order); |
- | |
1713 | } |
2487 | } |
- | 2488 | ||
- | 2489 | /* Write an elf, coff or "binary" file */ |
|
- | 2490 | static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, |
|
- | 2491 | ElfW(Phdr) *phdr, int file_offset, int *sec_order) |
|
- | 2492 | { |
|
- | 2493 | int fd, mode, file_type; |
|
- | 2494 | FILE *f; |
|
- | 2495 | ||
- | 2496 | file_type = s1->output_type; |
|
- | 2497 | if (file_type == TCC_OUTPUT_OBJ) |
|
- | 2498 | mode = 0666; |
|
- | 2499 | else |
|
- | 2500 | mode = 0777; |
|
- | 2501 | unlink(filename); |
|
- | 2502 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
|
- | 2503 | if (fd < 0) { |
|
- | 2504 | tcc_error_noabort("could not write '%s'", filename); |
|
- | 2505 | return -1; |
|
- | 2506 | } |
|
- | 2507 | f = fdopen(fd, "wb"); |
|
- | 2508 | if (s1->verbose) |
|
- | 2509 | printf("<- %s\n", filename); |
|
- | 2510 | ||
- | 2511 | #ifdef TCC_TARGET_COFF |
|
- | 2512 | if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) |
|
- | 2513 | tcc_output_coff(s1, f); |
|
- | 2514 | else |
|
- | 2515 | #endif |
|
- | 2516 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
|
- | 2517 | tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); |
|
- | 2518 | else |
|
- | 2519 | tcc_output_binary(s1, f, sec_order); |
|
1714 | fclose(f); |
2520 | fclose(f); |
Line 1715... | Line 2521... | ||
1715 | 2521 | ||
- | 2522 | return 0; |
|
- | 2523 | } |
|
- | 2524 | ||
- | 2525 | /* Output an elf, coff or binary file */ |
|
- | 2526 | /* XXX: suppress unneeded sections */ |
|
- | 2527 | static int elf_output_file(TCCState *s1, const char *filename) |
|
- | 2528 | { |
|
- | 2529 | int i, ret, phnum, shnum, file_type, file_offset, *sec_order; |
|
- | 2530 | struct dyn_inf dyninf; |
|
- | 2531 | ElfW(Phdr) *phdr; |
|
- | 2532 | ElfW(Sym) *sym; |
|
- | 2533 | Section *strsec, *interp, *dynamic, *dynstr; |
|
- | 2534 | ||
- | 2535 | file_type = s1->output_type; |
|
- | 2536 | s1->nb_errors = 0; |
|
- | 2537 | ||
- | 2538 | /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ |
|
- | 2539 | if (file_type != TCC_OUTPUT_OBJ) { |
|
- | 2540 | tcc_add_runtime(s1); |
|
- | 2541 | } |
|
- | 2542 | ||
- | 2543 | phdr = NULL; |
|
- | 2544 | sec_order = NULL; |
|
- | 2545 | interp = dynamic = dynstr = NULL; /* avoid warning */ |
|
- | 2546 | dyninf.dyn_rel_off = 0; /* avoid warning */ |
|
- | 2547 | ||
- | 2548 | if (file_type != TCC_OUTPUT_OBJ) { |
|
- | 2549 | relocate_common_syms(); |
|
- | 2550 | ||
- | 2551 | tcc_add_linker_symbols(s1); |
|
- | 2552 | ||
- | 2553 | if (!s1->static_link) { |
|
- | 2554 | if (file_type == TCC_OUTPUT_EXE) { |
|
- | 2555 | char *ptr; |
|
- | 2556 | /* allow override the dynamic loader */ |
|
- | 2557 | const char *elfint = getenv("LD_SO"); |
|
- | 2558 | if (elfint == NULL) |
|
- | 2559 | elfint = DEFAULT_ELFINTERP(s1); |
|
- | 2560 | /* add interpreter section only if executable */ |
|
- | 2561 | interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
|
- | 2562 | interp->sh_addralign = 1; |
|
- | 2563 | ptr = section_ptr_add(interp, 1 + strlen(elfint)); |
|
- | 2564 | strcpy(ptr, elfint); |
|
- | 2565 | } |
|
- | 2566 | ||
- | 2567 | /* add dynamic symbol table */ |
|
- | 2568 | s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
|
- | 2569 | ".dynstr", |
|
- | 2570 | ".hash", SHF_ALLOC); |
|
- | 2571 | dynstr = s1->dynsym->link; |
|
- | 2572 | ||
- | 2573 | /* add dynamic section */ |
|
- | 2574 | dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
|
- | 2575 | SHF_ALLOC | SHF_WRITE); |
|
- | 2576 | dynamic->link = dynstr; |
|
- | 2577 | dynamic->sh_entsize = sizeof(ElfW(Dyn)); |
|
- | 2578 | ||
- | 2579 | build_got(s1); |
|
- | 2580 | ||
- | 2581 | if (file_type == TCC_OUTPUT_EXE) { |
|
- | 2582 | bind_exe_dynsyms(s1); |
|
- | 2583 | ||
- | 2584 | if (s1->nb_errors) { |
|
- | 2585 | ret = -1; |
|
- | 2586 | goto the_end; |
|
- | 2587 | } |
|
- | 2588 | ||
- | 2589 | bind_libs_dynsyms(s1); |
|
- | 2590 | } else /* shared library case: simply export all global symbols */ |
|
- | 2591 | export_global_syms(s1); |
|
- | 2592 | ||
- | 2593 | build_got_entries(s1); |
|
- | 2594 | ||
- | 2595 | /* add a list of needed dlls */ |
|
- | 2596 | for(i = 0; i < s1->nb_loaded_dlls; i++) { |
|
- | 2597 | DLLReference *dllref = s1->loaded_dlls[i]; |
|
- | 2598 | if (dllref->level == 0) |
|
- | 2599 | put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
|
- | 2600 | } |
|
- | 2601 | ||
- | 2602 | if (s1->rpath) |
|
- | 2603 | put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); |
|
- | 2604 | ||
- | 2605 | /* XXX: currently, since we do not handle PIC code, we |
|
- | 2606 | must relocate the readonly segments */ |
|
- | 2607 | if (file_type == TCC_OUTPUT_DLL) { |
|
- | 2608 | if (s1->soname) |
|
- | 2609 | put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); |
|
- | 2610 | put_dt(dynamic, DT_TEXTREL, 0); |
|
- | 2611 | } |
|
- | 2612 | ||
- | 2613 | if (s1->symbolic) |
|
- | 2614 | put_dt(dynamic, DT_SYMBOLIC, 0); |
|
- | 2615 | ||
- | 2616 | /* add necessary space for other entries */ |
|
- | 2617 | dyninf.dyn_rel_off = dynamic->data_offset; |
|
- | 2618 | dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; |
|
- | 2619 | } else { |
|
- | 2620 | /* still need to build got entries in case of static link */ |
|
- | 2621 | build_got_entries(s1); |
|
- | 2622 | } |
|
- | 2623 | } |
|
- | 2624 | ||
- | 2625 | /* we add a section for symbols */ |
|
- | 2626 | strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
|
- | 2627 | put_elf_str(strsec, ""); |
|
- | 2628 | ||
- | 2629 | /* compute number of sections */ |
|
- | 2630 | shnum = s1->nb_sections; |
|
- | 2631 | ||
- | 2632 | /* this array is used to reorder sections in the output file */ |
|
- | 2633 | sec_order = tcc_malloc(sizeof(int) * shnum); |
|
- | 2634 | sec_order[0] = 0; |
|
- | 2635 | ||
- | 2636 | /* compute number of program headers */ |
|
- | 2637 | switch(file_type) { |
|
- | 2638 | default: |
|
- | 2639 | case TCC_OUTPUT_OBJ: |
|
- | 2640 | phnum = 0; |
|
- | 2641 | break; |
|
- | 2642 | case TCC_OUTPUT_EXE: |
|
- | 2643 | if (!s1->static_link) |
|
- | 2644 | phnum = 4 + HAVE_PHDR; |
|
- | 2645 | else |
|
- | 2646 | phnum = 2; |
|
- | 2647 | break; |
|
- | 2648 | case TCC_OUTPUT_DLL: |
|
- | 2649 | phnum = 3; |
|
- | 2650 | break; |
|
- | 2651 | } |
|
- | 2652 | ||
- | 2653 | /* Allocate strings for section names */ |
|
- | 2654 | alloc_sec_names(s1, file_type, strsec); |
|
- | 2655 | ||
- | 2656 | /* allocate program segment headers */ |
|
- | 2657 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
|
- | 2658 | ||
- | 2659 | /* compute section to program header mapping */ |
|
- | 2660 | file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, |
|
- | 2661 | sec_order); |
|
- | 2662 | ||
- | 2663 | /* Fill remaining program header and finalize relocation related to dynamic |
|
- | 2664 | linking. */ |
|
- | 2665 | if (phnum > 0) { |
|
- | 2666 | fill_unloadable_phdr(phdr, phnum, interp, dynamic); |
|
- | 2667 | if (dynamic) { |
|
- | 2668 | dyninf.dynamic = dynamic; |
|
- | 2669 | dyninf.dynstr = dynstr; |
|
- | 2670 | ||
- | 2671 | fill_dynamic(s1, &dyninf); |
|
- | 2672 | ||
- | 2673 | /* put in GOT the dynamic section address and relocate PLT */ |
|
- | 2674 | write32le(s1->got->data, dynamic->sh_addr); |
|
- | 2675 | if (file_type == TCC_OUTPUT_EXE |
|
- | 2676 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) |
|
- | 2677 | || file_type == TCC_OUTPUT_DLL |
|
- | 2678 | #endif |
|
- | 2679 | ) |
|
- | 2680 | relocate_plt(s1); |
|
- | 2681 | ||
- | 2682 | /* relocate symbols in .dynsym now that final addresses are known */ |
|
- | 2683 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { |
|
- | 2684 | if (sym->st_shndx == SHN_UNDEF) { |
|
- | 2685 | /* relocate to PLT if symbol corresponds to a PLT entry, |
|
- | 2686 | but not if it's a weak symbol */ |
|
- | 2687 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
|
- | 2688 | sym->st_value = 0; |
|
- | 2689 | else if (sym->st_value) |
|
- | 2690 | sym->st_value += s1->plt->sh_addr; |
|
- | 2691 | } else if (sym->st_shndx < SHN_LORESERVE) { |
|
- | 2692 | /* do symbol relocation */ |
|
- | 2693 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
|
- | 2694 | } |
|
- | 2695 | } |
|
- | 2696 | } |
|
- | 2697 | } |
|
- | 2698 | ||
- | 2699 | /* if building executable or DLL, then relocate each section |
|
- | 2700 | except the GOT which is already relocated */ |
|
- | 2701 | if (file_type != TCC_OUTPUT_OBJ) { |
|
- | 2702 | ret = final_sections_reloc(s1); |
|
- | 2703 | if (ret) |
|
- | 2704 | goto the_end; |
|
- | 2705 | } |
|
- | 2706 | ||
- | 2707 | /* Perform relocation to GOT or PLT entries */ |
|
- | 2708 | if (file_type == TCC_OUTPUT_EXE && s1->static_link) |
|
- | 2709 | fill_got(s1); |
|
- | 2710 | ||
- | 2711 | /* Create the ELF file with name 'filename' */ |
|
- | 2712 | ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); |
|
- | 2713 | if (s1->do_strip) { |
|
- | 2714 | int rc; |
|
- | 2715 | const char *strip_cmd = "sstrip "; // super strip utility from ELFkickers |
|
- | 2716 | const char *null_dev = " 2> /dev/null"; |
|
- | 2717 | char buf[1050]; |
|
- | 2718 | snprintf(buf, sizeof(buf), "%s%s%s", strip_cmd, filename, null_dev); |
|
- | 2719 | rc = system(buf); |
|
- | 2720 | if (rc) |
|
- | 2721 | system(buf+1); // call a strip utility from binutils |
|
1716 | ret = 0; |
2722 | } |
1717 | the_end: |
2723 | the_end: |
1718 | tcc_free(s1->symtab_to_dynsym); |
2724 | tcc_free(s1->symtab_to_dynsym); |
1719 | tcc_free(section_order); |
2725 | tcc_free(sec_order); |
1720 | tcc_free(phdr); |
2726 | tcc_free(phdr); |
- | 2727 | tcc_free(s1->sym_attrs); |
|
- | 2728 | s1->sym_attrs = NULL; |
|
- | 2729 | return ret; |
|
- | 2730 | } |
|
- | 2731 | ||
- | 2732 | LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) |
|
- | 2733 | { |
|
- | 2734 | int ret; |
|
- | 2735 | #ifdef TCC_TARGET_PE |
|
- | 2736 | if (s->output_type != TCC_OUTPUT_OBJ) { |
|
- | 2737 | ret = pe_output_file(s, filename); |
|
- | 2738 | } else |
|
- | 2739 | #elif defined TCC_TARGET_MEOS |
|
- | 2740 | if (s->output_type != TCC_OUTPUT_OBJ) { |
|
- | 2741 | ret = tcc_output_me(s, filename); |
|
- | 2742 | } else |
|
- | 2743 | #endif |
|
1721 | tcc_free(s1->got_offsets); |
2744 | ret = elf_output_file(s, filename); |
1722 | return ret; |
2745 | return ret; |
Line 1723... | Line 2746... | ||
1723 | } |
2746 | } |
1724 | 2747 | ||
Line 1739... | Line 2762... | ||
1739 | uint8_t link_once; /* true if link once section */ |
2762 | uint8_t link_once; /* true if link once section */ |
1740 | } SectionMergeInfo; |
2763 | } SectionMergeInfo; |
Line 1741... | Line 2764... | ||
1741 | 2764 | ||
1742 | /* load an object file and merge it with current files */ |
2765 | /* load an object file and merge it with current files */ |
1743 | /* XXX: handle correctly stab (debug) info */ |
2766 | /* XXX: handle correctly stab (debug) info */ |
1744 | static int tcc_load_object_file(TCCState *s1, |
2767 | ST_FUNC int tcc_load_object_file(TCCState *s1, |
1745 | int fd, unsigned long file_offset) |
2768 | int fd, unsigned long file_offset) |
1746 | { |
2769 | { |
1747 | Elf32_Ehdr ehdr; |
2770 | ElfW(Ehdr) ehdr; |
1748 | Elf32_Shdr *shdr, *sh; |
2771 | ElfW(Shdr) *shdr, *sh; |
1749 | int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
2772 | int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
1750 | unsigned char *strsec, *strtab; |
2773 | unsigned char *strsec, *strtab; |
1751 | int *old_to_new_syms; |
2774 | int *old_to_new_syms; |
1752 | char *sh_name, *name; |
2775 | char *sh_name, *name; |
1753 | SectionMergeInfo *sm_table, *sm; |
2776 | SectionMergeInfo *sm_table, *sm; |
1754 | Elf32_Sym *sym, *symtab; |
2777 | ElfW(Sym) *sym, *symtab; |
1755 | Elf32_Rel *rel, *rel_end; |
2778 | ElfW_Rel *rel; |
Line -... | Line 2779... | ||
- | 2779 | Section *s; |
|
- | 2780 | ||
- | 2781 | int stab_index; |
|
- | 2782 | int stabstr_index; |
|
- | 2783 | ||
1756 | Section *s; |
2784 | stab_index = stabstr_index = 0; |
1757 | 2785 | ||
1758 | if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
2786 | if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
1759 | goto fail1; |
2787 | goto fail1; |
1760 | if (ehdr.e_ident[0] != ELFMAG0 || |
2788 | if (ehdr.e_ident[0] != ELFMAG0 || |
Line 1767... | Line 2795... | ||
1767 | goto fail1; |
2795 | goto fail1; |
1768 | /* test CPU specific stuff */ |
2796 | /* test CPU specific stuff */ |
1769 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
2797 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
1770 | ehdr.e_machine != EM_TCC_TARGET) { |
2798 | ehdr.e_machine != EM_TCC_TARGET) { |
1771 | fail1: |
2799 | fail1: |
1772 | error_noabort("invalid object file"); |
2800 | tcc_error_noabort("invalid object file"); |
1773 | return -1; |
2801 | return -1; |
1774 | } |
2802 | } |
1775 | /* read sections */ |
2803 | /* read sections */ |
1776 | shdr = load_data(fd, file_offset + ehdr.e_shoff, |
2804 | shdr = load_data(fd, file_offset + ehdr.e_shoff, |
1777 | sizeof(Elf32_Shdr) * ehdr.e_shnum); |
2805 | sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
1778 | sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
2806 | sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
Line 1779... | Line 2807... | ||
1779 | 2807 | ||
1780 | /* load section names */ |
2808 | /* load section names */ |
1781 | sh = &shdr[ehdr.e_shstrndx]; |
2809 | sh = &shdr[ehdr.e_shstrndx]; |
Line 1788... | Line 2816... | ||
1788 | nb_syms = 0; |
2816 | nb_syms = 0; |
1789 | for(i = 1; i < ehdr.e_shnum; i++) { |
2817 | for(i = 1; i < ehdr.e_shnum; i++) { |
1790 | sh = &shdr[i]; |
2818 | sh = &shdr[i]; |
1791 | if (sh->sh_type == SHT_SYMTAB) { |
2819 | if (sh->sh_type == SHT_SYMTAB) { |
1792 | if (symtab) { |
2820 | if (symtab) { |
1793 | error_noabort("object must contain only one symtab"); |
2821 | tcc_error_noabort("object must contain only one symtab"); |
1794 | fail: |
2822 | fail: |
1795 | ret = -1; |
2823 | ret = -1; |
1796 | goto the_end; |
2824 | goto the_end; |
1797 | } |
2825 | } |
1798 | nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
2826 | nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
1799 | symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
2827 | symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
1800 | sm_table[i].s = symtab_section; |
2828 | sm_table[i].s = symtab_section; |
Line 1801... | Line 2829... | ||
1801 | 2829 | ||
1802 | /* now load strtab */ |
2830 | /* now load strtab */ |
Line 1810... | Line 2838... | ||
1810 | for(i = 1; i < ehdr.e_shnum; i++) { |
2838 | for(i = 1; i < ehdr.e_shnum; i++) { |
1811 | /* no need to examine section name strtab */ |
2839 | /* no need to examine section name strtab */ |
1812 | if (i == ehdr.e_shstrndx) |
2840 | if (i == ehdr.e_shstrndx) |
1813 | continue; |
2841 | continue; |
1814 | sh = &shdr[i]; |
2842 | sh = &shdr[i]; |
1815 | sh_name = strsec + sh->sh_name; |
2843 | sh_name = (char *) strsec + sh->sh_name; |
1816 | /* ignore sections types we do not handle */ |
2844 | /* ignore sections types we do not handle */ |
1817 | if (sh->sh_type != SHT_PROGBITS && |
2845 | if (sh->sh_type != SHT_PROGBITS && |
1818 | sh->sh_type != SHT_REL && |
2846 | sh->sh_type != SHT_RELX && |
- | 2847 | #ifdef TCC_ARM_EABI |
|
- | 2848 | sh->sh_type != SHT_ARM_EXIDX && |
|
- | 2849 | #endif |
|
1819 | sh->sh_type != SHT_NOBITS) |
2850 | sh->sh_type != SHT_NOBITS && |
- | 2851 | sh->sh_type != SHT_PREINIT_ARRAY && |
|
- | 2852 | sh->sh_type != SHT_INIT_ARRAY && |
|
- | 2853 | sh->sh_type != SHT_FINI_ARRAY && |
|
- | 2854 | strcmp(sh_name, ".stabstr") |
|
- | 2855 | ) |
|
1820 | continue; |
2856 | continue; |
1821 | if (sh->sh_addralign < 1) |
2857 | if (sh->sh_addralign < 1) |
1822 | sh->sh_addralign = 1; |
2858 | sh->sh_addralign = 1; |
1823 | /* find corresponding section, if any */ |
2859 | /* find corresponding section, if any */ |
1824 | for(j = 1; j < s1->nb_sections;j++) { |
2860 | for(j = 1; j < s1->nb_sections;j++) { |
Line 1844... | Line 2880... | ||
1844 | s->sh_addralign = sh->sh_addralign; |
2880 | s->sh_addralign = sh->sh_addralign; |
1845 | s->sh_entsize = sh->sh_entsize; |
2881 | s->sh_entsize = sh->sh_entsize; |
1846 | sm_table[i].new_section = 1; |
2882 | sm_table[i].new_section = 1; |
1847 | found: |
2883 | found: |
1848 | if (sh->sh_type != s->sh_type) { |
2884 | if (sh->sh_type != s->sh_type) { |
1849 | error_noabort("invalid section type"); |
2885 | tcc_error_noabort("invalid section type"); |
1850 | goto fail; |
2886 | goto fail; |
1851 | } |
2887 | } |
Line 1852... | Line 2888... | ||
1852 | 2888 | ||
1853 | /* align start of section */ |
2889 | /* align start of section */ |
- | 2890 | offset = s->data_offset; |
|
- | 2891 | ||
- | 2892 | if (0 == strcmp(sh_name, ".stab")) { |
|
- | 2893 | stab_index = i; |
|
- | 2894 | goto no_align; |
|
- | 2895 | } |
|
- | 2896 | if (0 == strcmp(sh_name, ".stabstr")) { |
|
- | 2897 | stabstr_index = i; |
|
- | 2898 | goto no_align; |
|
- | 2899 | } |
|
1854 | offset = s->data_offset; |
2900 | |
1855 | size = sh->sh_addralign - 1; |
2901 | size = sh->sh_addralign - 1; |
1856 | offset = (offset + size) & ~size; |
2902 | offset = (offset + size) & ~size; |
1857 | if (sh->sh_addralign > s->sh_addralign) |
2903 | if (sh->sh_addralign > s->sh_addralign) |
1858 | s->sh_addralign = sh->sh_addralign; |
2904 | s->sh_addralign = sh->sh_addralign; |
- | 2905 | s->data_offset = offset; |
|
1859 | s->data_offset = offset; |
2906 | no_align: |
1860 | sm_table[i].offset = offset; |
2907 | sm_table[i].offset = offset; |
1861 | sm_table[i].s = s; |
2908 | sm_table[i].s = s; |
1862 | /* concatenate sections */ |
2909 | /* concatenate sections */ |
1863 | size = sh->sh_size; |
2910 | size = sh->sh_size; |
Line 1870... | Line 2917... | ||
1870 | s->data_offset += size; |
2917 | s->data_offset += size; |
1871 | } |
2918 | } |
1872 | next: ; |
2919 | next: ; |
1873 | } |
2920 | } |
Line -... | Line 2921... | ||
- | 2921 | ||
- | 2922 | /* gr relocate stab strings */ |
|
- | 2923 | if (stab_index && stabstr_index) { |
|
- | 2924 | Stab_Sym *a, *b; |
|
- | 2925 | unsigned o; |
|
- | 2926 | s = sm_table[stab_index].s; |
|
- | 2927 | a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); |
|
- | 2928 | b = (Stab_Sym *)(s->data + s->data_offset); |
|
- | 2929 | o = sm_table[stabstr_index].offset; |
|
- | 2930 | while (a < b) |
|
- | 2931 | a->n_strx += o, a++; |
|
- | 2932 | } |
|
1874 | 2933 | ||
1875 | /* second short pass to update sh_link and sh_info fields of new |
2934 | /* second short pass to update sh_link and sh_info fields of new |
1876 | sections */ |
- | |
1877 | sm = sm_table; |
2935 | sections */ |
1878 | for(i = 1; i < ehdr.e_shnum; i++) { |
2936 | for(i = 1; i < ehdr.e_shnum; i++) { |
1879 | s = sm_table[i].s; |
2937 | s = sm_table[i].s; |
1880 | if (!s || !sm_table[i].new_section) |
2938 | if (!s || !sm_table[i].new_section) |
1881 | continue; |
2939 | continue; |
1882 | sh = &shdr[i]; |
2940 | sh = &shdr[i]; |
1883 | if (sh->sh_link > 0) |
2941 | if (sh->sh_link > 0) |
1884 | s->link = sm_table[sh->sh_link].s; |
2942 | s->link = sm_table[sh->sh_link].s; |
1885 | if (sh->sh_type == SHT_REL) { |
2943 | if (sh->sh_type == SHT_RELX) { |
1886 | s->sh_info = sm_table[sh->sh_info].s->sh_num; |
2944 | s->sh_info = sm_table[sh->sh_info].s->sh_num; |
1887 | /* update backward link */ |
2945 | /* update backward link */ |
1888 | s1->sections[s->sh_info]->reloc = s; |
2946 | s1->sections[s->sh_info]->reloc = s; |
1889 | } |
2947 | } |
- | 2948 | } |
|
Line 1890... | Line 2949... | ||
1890 | } |
2949 | sm = sm_table; |
1891 | 2950 | ||
Line 1892... | Line 2951... | ||
1892 | /* resolve symbols */ |
2951 | /* resolve symbols */ |
Line 1899... | Line 2958... | ||
1899 | sm = &sm_table[sym->st_shndx]; |
2958 | sm = &sm_table[sym->st_shndx]; |
1900 | if (sm->link_once) { |
2959 | if (sm->link_once) { |
1901 | /* if a symbol is in a link once section, we use the |
2960 | /* if a symbol is in a link once section, we use the |
1902 | already defined symbol. It is very important to get |
2961 | already defined symbol. It is very important to get |
1903 | correct relocations */ |
2962 | correct relocations */ |
1904 | if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
2963 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
1905 | name = strtab + sym->st_name; |
2964 | name = (char *) strtab + sym->st_name; |
1906 | sym_index = find_elf_sym(symtab_section, name); |
2965 | sym_index = find_elf_sym(symtab_section, name); |
1907 | if (sym_index) |
2966 | if (sym_index) |
1908 | old_to_new_syms[i] = sym_index; |
2967 | old_to_new_syms[i] = sym_index; |
1909 | } |
2968 | } |
1910 | continue; |
2969 | continue; |
Line 1916... | Line 2975... | ||
1916 | sym->st_shndx = sm->s->sh_num; |
2975 | sym->st_shndx = sm->s->sh_num; |
1917 | /* offset value */ |
2976 | /* offset value */ |
1918 | sym->st_value += sm->offset; |
2977 | sym->st_value += sm->offset; |
1919 | } |
2978 | } |
1920 | /* add symbol */ |
2979 | /* add symbol */ |
1921 | name = strtab + sym->st_name; |
2980 | name = (char *) strtab + sym->st_name; |
1922 | sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, |
2981 | sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, |
1923 | sym->st_info, sym->st_other, |
2982 | sym->st_info, sym->st_other, |
1924 | sym->st_shndx, name); |
2983 | sym->st_shndx, name); |
1925 | old_to_new_syms[i] = sym_index; |
2984 | old_to_new_syms[i] = sym_index; |
1926 | } |
2985 | } |
Line 1931... | Line 2990... | ||
1931 | if (!s) |
2990 | if (!s) |
1932 | continue; |
2991 | continue; |
1933 | sh = &shdr[i]; |
2992 | sh = &shdr[i]; |
1934 | offset = sm_table[i].offset; |
2993 | offset = sm_table[i].offset; |
1935 | switch(s->sh_type) { |
2994 | switch(s->sh_type) { |
1936 | case SHT_REL: |
2995 | case SHT_RELX: |
1937 | /* take relocation offset information */ |
2996 | /* take relocation offset information */ |
1938 | offseti = sm_table[sh->sh_info].offset; |
2997 | offseti = sm_table[sh->sh_info].offset; |
1939 | rel_end = (Elf32_Rel *)(s->data + s->data_offset); |
- | |
1940 | for(rel = (Elf32_Rel *)(s->data + offset); |
2998 | for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) { |
1941 | rel < rel_end; |
- | |
1942 | rel++) { |
- | |
1943 | int type; |
2999 | int type; |
1944 | unsigned sym_index; |
3000 | unsigned sym_index; |
1945 | /* convert symbol index */ |
3001 | /* convert symbol index */ |
1946 | type = ELF32_R_TYPE(rel->r_info); |
3002 | type = ELFW(R_TYPE)(rel->r_info); |
1947 | sym_index = ELF32_R_SYM(rel->r_info); |
3003 | sym_index = ELFW(R_SYM)(rel->r_info); |
1948 | /* NOTE: only one symtab assumed */ |
3004 | /* NOTE: only one symtab assumed */ |
1949 | if (sym_index >= nb_syms) |
3005 | if (sym_index >= nb_syms) |
1950 | goto invalid_reloc; |
3006 | goto invalid_reloc; |
1951 | sym_index = old_to_new_syms[sym_index]; |
3007 | sym_index = old_to_new_syms[sym_index]; |
- | 3008 | /* ignore link_once in rel section. */ |
|
1952 | if (!sym_index) { |
3009 | if (!sym_index && !sm->link_once |
- | 3010 | #ifdef TCC_TARGET_ARM |
|
- | 3011 | && type != R_ARM_V4BX |
|
- | 3012 | #endif |
|
- | 3013 | ) { |
|
1953 | invalid_reloc: |
3014 | invalid_reloc: |
1954 | error_noabort("Invalid relocation entry"); |
3015 | tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", |
- | 3016 | i, strsec + sh->sh_name, rel->r_offset); |
|
1955 | goto fail; |
3017 | goto fail; |
1956 | } |
3018 | } |
1957 | rel->r_info = ELF32_R_INFO(sym_index, type); |
3019 | rel->r_info = ELFW(R_INFO)(sym_index, type); |
1958 | /* offset the relocation offset */ |
3020 | /* offset the relocation offset */ |
1959 | rel->r_offset += offseti; |
3021 | rel->r_offset += offseti; |
- | 3022 | #ifdef TCC_TARGET_ARM |
|
- | 3023 | /* Jumps and branches from a Thumb code to a PLT entry need |
|
- | 3024 | special handling since PLT entries are ARM code. |
|
- | 3025 | Unconditional bl instructions referencing PLT entries are |
|
- | 3026 | handled by converting these instructions into blx |
|
- | 3027 | instructions. Other case of instructions referencing a PLT |
|
- | 3028 | entry require to add a Thumb stub before the PLT entry to |
|
- | 3029 | switch to ARM mode. We set bit plt_thumb_stub of the |
|
- | 3030 | attribute of a symbol to indicate such a case. */ |
|
- | 3031 | if (type == R_ARM_THM_JUMP24) |
|
- | 3032 | alloc_sym_attr(s1, sym_index)->plt_thumb_stub = 1; |
|
- | 3033 | #endif |
|
1960 | } |
3034 | } |
1961 | break; |
3035 | break; |
1962 | default: |
3036 | default: |
1963 | break; |
3037 | break; |
1964 | } |
3038 | } |
Line 1973... | Line 3047... | ||
1973 | tcc_free(strsec); |
3047 | tcc_free(strsec); |
1974 | tcc_free(shdr); |
3048 | tcc_free(shdr); |
1975 | return ret; |
3049 | return ret; |
1976 | } |
3050 | } |
Line 1977... | Line -... | ||
1977 | - | ||
1978 | #define ARMAG "! |
- | |
1979 | 3051 | ||
1980 | typedef struct ArchiveHeader { |
3052 | typedef struct ArchiveHeader { |
1981 | char ar_name[16]; /* name of this member */ |
3053 | char ar_name[16]; /* name of this member */ |
1982 | char ar_date[12]; /* file mtime */ |
3054 | char ar_date[12]; /* file mtime */ |
1983 | char ar_uid[6]; /* owner uid; printed as decimal */ |
3055 | char ar_uid[6]; /* owner uid; printed as decimal */ |
Line 1997... | Line 3069... | ||
1997 | { |
3069 | { |
1998 | int i, bound, nsyms, sym_index, off, ret; |
3070 | int i, bound, nsyms, sym_index, off, ret; |
1999 | uint8_t *data; |
3071 | uint8_t *data; |
2000 | const char *ar_names, *p; |
3072 | const char *ar_names, *p; |
2001 | const uint8_t *ar_index; |
3073 | const uint8_t *ar_index; |
2002 | Elf32_Sym *sym; |
3074 | ElfW(Sym) *sym; |
Line 2003... | Line 3075... | ||
2003 | 3075 | ||
2004 | data = tcc_malloc(size); |
3076 | data = tcc_malloc(size); |
2005 | if (read(fd, data, size) != size) |
3077 | if (read(fd, data, size) != size) |
2006 | goto fail; |
3078 | goto fail; |
2007 | nsyms = get_be32(data); |
3079 | nsyms = get_be32(data); |
2008 | ar_index = data + 4; |
3080 | ar_index = data + 4; |
Line 2009... | Line 3081... | ||
2009 | ar_names = ar_index + nsyms * 4; |
3081 | ar_names = (char *) ar_index + nsyms * 4; |
2010 | 3082 | ||
2011 | do { |
3083 | do { |
2012 | bound = 0; |
3084 | bound = 0; |
2013 | for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { |
3085 | for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { |
2014 | sym_index = find_elf_sym(symtab_section, p); |
3086 | sym_index = find_elf_sym(symtab_section, p); |
2015 | if(sym_index) { |
3087 | if(sym_index) { |
2016 | sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
3088 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2017 | if(sym->st_shndx == SHN_UNDEF) { |
- | |
2018 | off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); |
- | |
2019 | #if 0 |
- | |
2020 | printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); |
3089 | if(sym->st_shndx == SHN_UNDEF) { |
2021 | #endif |
3090 | off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); |
2022 | ++bound; |
3091 | ++bound; |
2023 | lseek(fd, off, SEEK_SET); |
3092 | lseek(fd, off, SEEK_SET); |
2024 | if(tcc_load_object_file(s1, fd, off) < 0) { |
3093 | if(tcc_load_object_file(s1, fd, off) < 0) { |
Line 2035... | Line 3104... | ||
2035 | tcc_free(data); |
3104 | tcc_free(data); |
2036 | return ret; |
3105 | return ret; |
2037 | } |
3106 | } |
Line 2038... | Line 3107... | ||
2038 | 3107 | ||
2039 | /* load a '.a' file */ |
3108 | /* load a '.a' file */ |
2040 | static int tcc_load_archive(TCCState *s1, int fd) |
3109 | ST_FUNC int tcc_load_archive(TCCState *s1, int fd) |
2041 | { |
3110 | { |
2042 | ArchiveHeader hdr; |
3111 | ArchiveHeader hdr; |
2043 | char ar_size[11]; |
3112 | char ar_size[11]; |
2044 | char ar_name[17]; |
3113 | char ar_name[17]; |
Line 2052... | Line 3121... | ||
2052 | for(;;) { |
3121 | for(;;) { |
2053 | len = read(fd, &hdr, sizeof(hdr)); |
3122 | len = read(fd, &hdr, sizeof(hdr)); |
2054 | if (len == 0) |
3123 | if (len == 0) |
2055 | break; |
3124 | break; |
2056 | if (len != sizeof(hdr)) { |
3125 | if (len != sizeof(hdr)) { |
2057 | error_noabort("invalid archive"); |
3126 | tcc_error_noabort("invalid archive"); |
2058 | return -1; |
3127 | return -1; |
2059 | } |
3128 | } |
2060 | memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
3129 | memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
2061 | ar_size[sizeof(hdr.ar_size)] = '\0'; |
3130 | ar_size[sizeof(hdr.ar_size)] = '\0'; |
2062 | size = strtol(ar_size, NULL, 0); |
3131 | size = strtol(ar_size, NULL, 0); |
Line 2064... | Line 3133... | ||
2064 | for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { |
3133 | for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { |
2065 | if (ar_name[i] != ' ') |
3134 | if (ar_name[i] != ' ') |
2066 | break; |
3135 | break; |
2067 | } |
3136 | } |
2068 | ar_name[i + 1] = '\0'; |
3137 | ar_name[i + 1] = '\0'; |
2069 | // printf("name='%s' size=%d %s\n", ar_name, size, ar_size); |
- | |
2070 | file_offset = lseek(fd, 0, SEEK_CUR); |
3138 | file_offset = lseek(fd, 0, SEEK_CUR); |
2071 | /* align to even */ |
3139 | /* align to even */ |
2072 | size = (size + 1) & ~1; |
3140 | size = (size + 1) & ~1; |
2073 | if (!strcmp(ar_name, "/")) { |
3141 | if (!strcmp(ar_name, "/")) { |
2074 | /* coff symbol table : we handle it */ |
3142 | /* coff symbol table : we handle it */ |
Line 2086... | Line 3154... | ||
2086 | lseek(fd, file_offset + size, SEEK_SET); |
3154 | lseek(fd, file_offset + size, SEEK_SET); |
2087 | } |
3155 | } |
2088 | return 0; |
3156 | return 0; |
2089 | } |
3157 | } |
Line -... | Line 3158... | ||
- | 3158 | ||
2090 | 3159 | #if !defined(TCC_TARGET_PE) && !defined(TCC_TARGET_MEOS) |
|
2091 | /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL |
3160 | /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL |
2092 | is referenced by the user (so it should be added as DT_NEEDED in |
3161 | is referenced by the user (so it should be added as DT_NEEDED in |
2093 | the generated ELF file) */ |
3162 | the generated ELF file) */ |
2094 | static int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
3163 | ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
2095 | { |
3164 | { |
2096 | Elf32_Ehdr ehdr; |
3165 | ElfW(Ehdr) ehdr; |
2097 | Elf32_Shdr *shdr, *sh, *sh1; |
3166 | ElfW(Shdr) *shdr, *sh, *sh1; |
2098 | int i, nb_syms, nb_dts, sym_bind, ret; |
3167 | int i, j, nb_syms, nb_dts, sym_bind, ret; |
2099 | Elf32_Sym *sym, *dynsym; |
3168 | ElfW(Sym) *sym, *dynsym; |
2100 | Elf32_Dyn *dt, *dynamic; |
3169 | ElfW(Dyn) *dt, *dynamic; |
2101 | unsigned char *dynstr; |
3170 | unsigned char *dynstr; |
2102 | const char *name, *soname, *p; |
3171 | const char *name, *soname; |
Line 2103... | Line 3172... | ||
2103 | DLLReference *dllref; |
3172 | DLLReference *dllref; |
Line 2104... | Line 3173... | ||
2104 | 3173 | ||
2105 | read(fd, &ehdr, sizeof(ehdr)); |
3174 | read(fd, &ehdr, sizeof(ehdr)); |
2106 | 3175 | ||
2107 | /* test CPU specific stuff */ |
3176 | /* test CPU specific stuff */ |
2108 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
3177 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
2109 | ehdr.e_machine != EM_TCC_TARGET) { |
3178 | ehdr.e_machine != EM_TCC_TARGET) { |
Line 2110... | Line 3179... | ||
2110 | error_noabort("bad architecture"); |
3179 | tcc_error_noabort("bad architecture"); |
2111 | return -1; |
3180 | return -1; |
Line 2112... | Line 3181... | ||
2112 | } |
3181 | } |
2113 | 3182 | ||
2114 | /* read sections */ |
3183 | /* read sections */ |
2115 | shdr = load_data(fd, ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); |
3184 | shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
2116 | 3185 | ||
2117 | /* load dynamic section and dynamic symbols */ |
3186 | /* load dynamic section and dynamic symbols */ |
2118 | nb_syms = 0; |
3187 | nb_syms = 0; |
2119 | nb_dts = 0; |
3188 | nb_dts = 0; |
2120 | dynamic = NULL; |
3189 | dynamic = NULL; |
2121 | dynsym = NULL; /* avoid warning */ |
3190 | dynsym = NULL; /* avoid warning */ |
2122 | dynstr = NULL; /* avoid warning */ |
3191 | dynstr = NULL; /* avoid warning */ |
2123 | for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { |
3192 | for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { |
2124 | switch(sh->sh_type) { |
3193 | switch(sh->sh_type) { |
2125 | case SHT_DYNAMIC: |
3194 | case SHT_DYNAMIC: |
2126 | nb_dts = sh->sh_size / sizeof(Elf32_Dyn); |
3195 | nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); |
2127 | dynamic = load_data(fd, sh->sh_offset, sh->sh_size); |
3196 | dynamic = load_data(fd, sh->sh_offset, sh->sh_size); |
2128 | break; |
3197 | break; |
2129 | case SHT_DYNSYM: |
3198 | case SHT_DYNSYM: |
2130 | nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
3199 | nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
2131 | dynsym = load_data(fd, sh->sh_offset, sh->sh_size); |
3200 | dynsym = load_data(fd, sh->sh_offset, sh->sh_size); |
2132 | sh1 = &shdr[sh->sh_link]; |
3201 | sh1 = &shdr[sh->sh_link]; |
2133 | dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); |
3202 | dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); |
Line 2134... | Line 3203... | ||
2134 | break; |
3203 | break; |
2135 | default: |
3204 | default: |
2136 | break; |
- | |
2137 | } |
- | |
2138 | } |
- | |
Line 2139... | Line 3205... | ||
2139 | 3205 | break; |
|
2140 | /* compute the real library name */ |
3206 | } |
2141 | soname = filename; |
3207 | } |
2142 | p = strrchr(soname, '/'); |
3208 | |
2143 | if (p) |
3209 | /* compute the real library name */ |
Line 2144... | Line 3210... | ||
2144 | soname = p + 1; |
3210 | soname = tcc_basename(filename); |
2145 | 3211 | ||
Line 2159... | Line 3225... | ||
2159 | ret = 0; |
3225 | ret = 0; |
2160 | goto the_end; |
3226 | goto the_end; |
2161 | } |
3227 | } |
2162 | } |
3228 | } |
Line 2163... | Line -... | ||
2163 | - | ||
2164 | // printf("loading dll '%s'\n", soname); |
- | |
2165 | 3229 | ||
2166 | /* add the dll and its level */ |
3230 | /* add the dll and its level */ |
2167 | dllref = tcc_malloc(sizeof(DLLReference) + strlen(soname)); |
3231 | dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); |
2168 | dllref->level = level; |
3232 | dllref->level = level; |
2169 | strcpy(dllref->name, soname); |
3233 | strcpy(dllref->name, soname); |
Line 2170... | Line 3234... | ||
2170 | dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
3234 | dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
2171 | 3235 | ||
2172 | /* add dynamic symbols in dynsym_section */ |
3236 | /* add dynamic symbols in dynsym_section */ |
2173 | for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { |
3237 | for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { |
2174 | sym_bind = ELF32_ST_BIND(sym->st_info); |
3238 | sym_bind = ELFW(ST_BIND)(sym->st_info); |
2175 | if (sym_bind == STB_LOCAL) |
3239 | if (sym_bind == STB_LOCAL) |
2176 | continue; |
3240 | continue; |
2177 | name = dynstr + sym->st_name; |
3241 | name = (char *) dynstr + sym->st_name; |
2178 | add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
3242 | add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
Line 2179... | Line 3243... | ||
2179 | sym->st_info, sym->st_other, sym->st_shndx, name); |
3243 | sym->st_info, sym->st_other, sym->st_shndx, name); |
2180 | } |
3244 | } |
2181 | 3245 | ||
2182 | /* load all referenced DLLs */ |
3246 | /* load all referenced DLLs */ |
2183 | for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
3247 | for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
2184 | switch(dt->d_tag) { |
3248 | switch(dt->d_tag) { |
2185 | case DT_NEEDED: |
3249 | case DT_NEEDED: |
2186 | name = dynstr + dt->d_un.d_val; |
3250 | name = (char *) dynstr + dt->d_un.d_val; |
2187 | for(i = 0; i < s1->nb_loaded_dlls; i++) { |
3251 | for(j = 0; j < s1->nb_loaded_dlls; j++) { |
2188 | dllref = s1->loaded_dlls[i]; |
3252 | dllref = s1->loaded_dlls[j]; |
2189 | if (!strcmp(name, dllref->name)) |
3253 | if (!strcmp(name, dllref->name)) |
2190 | goto already_loaded; |
3254 | goto already_loaded; |
2191 | } |
3255 | } |
2192 | if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
3256 | if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
2193 | error_noabort("referenced dll '%s' not found", name); |
3257 | tcc_error_noabort("referenced dll '%s' not found", name); |
2194 | ret = -1; |
3258 | ret = -1; |
2195 | goto the_end; |
3259 | goto the_end; |
Line 2222... | Line 3286... | ||
2222 | case '\t': |
3286 | case '\t': |
2223 | case '\f': |
3287 | case '\f': |
2224 | case '\v': |
3288 | case '\v': |
2225 | case '\r': |
3289 | case '\r': |
2226 | case '\n': |
3290 | case '\n': |
2227 | input(); |
3291 | inp(); |
2228 | goto redo; |
3292 | goto redo; |
2229 | case '/': |
3293 | case '/': |
2230 | minp(); |
3294 | minp(); |
2231 | if (ch == '*') { |
3295 | if (ch == '*') { |
2232 | file->buf_ptr = parse_comment(file->buf_ptr); |
3296 | file->buf_ptr = parse_comment(file->buf_ptr,0); |
2233 | ch = file->buf_ptr[0]; |
3297 | ch = file->buf_ptr[0]; |
2234 | goto redo; |
3298 | goto redo; |
2235 | } else { |
3299 | } else { |
2236 | q = name; |
3300 | q = name; |
2237 | *q++ = '/'; |
3301 | *q++ = '/'; |
2238 | goto parse_name; |
3302 | goto parse_name; |
2239 | } |
3303 | } |
2240 | break; |
3304 | break; |
2241 | case 'a' ... 'z': |
- | |
2242 | case 'A' ... 'Z': |
- | |
2243 | case '_': |
- | |
2244 | case '\\': |
3305 | case '\\': |
- | 3306 | ch = handle_eob(); |
|
- | 3307 | if (ch != '\\') |
|
- | 3308 | goto redo; |
|
- | 3309 | /* fall through */ |
|
- | 3310 | /* case 'a' ... 'z': */ |
|
- | 3311 | case 'a': |
|
- | 3312 | case 'b': |
|
- | 3313 | case 'c': |
|
- | 3314 | case 'd': |
|
- | 3315 | case 'e': |
|
- | 3316 | case 'f': |
|
- | 3317 | case 'g': |
|
- | 3318 | case 'h': |
|
- | 3319 | case 'i': |
|
- | 3320 | case 'j': |
|
- | 3321 | case 'k': |
|
- | 3322 | case 'l': |
|
- | 3323 | case 'm': |
|
- | 3324 | case 'n': |
|
- | 3325 | case 'o': |
|
- | 3326 | case 'p': |
|
- | 3327 | case 'q': |
|
- | 3328 | case 'r': |
|
- | 3329 | case 's': |
|
- | 3330 | case 't': |
|
- | 3331 | case 'u': |
|
- | 3332 | case 'v': |
|
- | 3333 | case 'w': |
|
- | 3334 | case 'x': |
|
- | 3335 | case 'y': |
|
- | 3336 | case 'z': |
|
- | 3337 | /* case 'A' ... 'z': */ |
|
- | 3338 | case 'A': |
|
- | 3339 | case 'B': |
|
- | 3340 | case 'C': |
|
- | 3341 | case 'D': |
|
- | 3342 | case 'E': |
|
- | 3343 | case 'F': |
|
- | 3344 | case 'G': |
|
- | 3345 | case 'H': |
|
- | 3346 | case 'I': |
|
- | 3347 | case 'J': |
|
- | 3348 | case 'K': |
|
- | 3349 | case 'L': |
|
- | 3350 | case 'M': |
|
- | 3351 | case 'N': |
|
- | 3352 | case 'O': |
|
- | 3353 | case 'P': |
|
- | 3354 | case 'Q': |
|
- | 3355 | case 'R': |
|
- | 3356 | case 'S': |
|
- | 3357 | case 'T': |
|
- | 3358 | case 'U': |
|
- | 3359 | case 'V': |
|
- | 3360 | case 'W': |
|
- | 3361 | case 'X': |
|
- | 3362 | case 'Y': |
|
- | 3363 | case 'Z': |
|
- | 3364 | case '_': |
|
2245 | case '.': |
3365 | case '.': |
2246 | case '$': |
3366 | case '$': |
2247 | case '~': |
3367 | case '~': |
2248 | q = name; |
3368 | q = name; |
2249 | parse_name: |
3369 | parse_name: |
Line 2264... | Line 3384... | ||
2264 | case CH_EOF: |
3384 | case CH_EOF: |
2265 | c = LD_TOK_EOF; |
3385 | c = LD_TOK_EOF; |
2266 | break; |
3386 | break; |
2267 | default: |
3387 | default: |
2268 | c = ch; |
3388 | c = ch; |
2269 | input(); |
3389 | inp(); |
2270 | break; |
3390 | break; |
2271 | } |
3391 | } |
2272 | #if 0 |
- | |
2273 | printf("tok=%c %d\n", c, c); |
- | |
2274 | if (c == LD_TOK_NAME) |
- | |
2275 | printf(" name=%s\n", name); |
- | |
2276 | #endif |
- | |
2277 | return c; |
3392 | return c; |
2278 | } |
3393 | } |
Line 2279... | Line -... | ||
2279 | - | ||
2280 | /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
- | |
2281 | files */ |
3394 | |
2282 | static int tcc_load_ldscript(TCCState *s1) |
3395 | static int ld_add_file(TCCState *s1, const char filename[]) |
2283 | { |
- | |
2284 | char cmd[64]; |
- | |
2285 | char filename[1024]; |
3396 | { |
Line -... | Line 3397... | ||
- | 3397 | int ret; |
|
- | 3398 | ||
2286 | int t; |
3399 | ret = tcc_add_file_internal(s1, filename, 0, TCC_FILETYPE_BINARY); |
2287 | 3400 | if (ret) |
|
- | 3401 | ret = tcc_add_dll(s1, filename, 0); |
|
- | 3402 | return ret; |
|
- | 3403 | } |
|
- | 3404 | ||
2288 | ch = file->buf_ptr[0]; |
3405 | static inline int new_undef_syms(void) |
2289 | ch = handle_eob(); |
3406 | { |
2290 | for(;;) { |
3407 | int ret = 0; |
2291 | t = ld_next(s1, cmd, sizeof(cmd)); |
3408 | ret = new_undef_sym; |
- | 3409 | new_undef_sym = 0; |
|
- | 3410 | return ret; |
|
- | 3411 | } |
|
- | 3412 | ||
- | 3413 | static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) |
|
2292 | if (t == LD_TOK_EOF) |
3414 | { |
2293 | return 0; |
3415 | char filename[1024], libname[1024]; |
- | 3416 | int t, group, nblibs = 0, ret = 0; |
|
2294 | else if (t != LD_TOK_NAME) |
3417 | char **libs = NULL; |
- | 3418 | ||
2295 | return -1; |
3419 | group = !strcmp(cmd, "GROUP"); |
2296 | if (!strcmp(cmd, "INPUT") || |
3420 | if (!as_needed) |
2297 | !strcmp(cmd, "GROUP")) { |
3421 | new_undef_syms(); |
2298 | t = ld_next(s1, cmd, sizeof(cmd)); |
3422 | t = ld_next(s1, filename, sizeof(filename)); |
2299 | if (t != '(') |
3423 | if (t != '(') |
2300 | expect("("); |
3424 | expect("("); |
- | 3425 | t = ld_next(s1, filename, sizeof(filename)); |
|
2301 | t = ld_next(s1, filename, sizeof(filename)); |
3426 | for(;;) { |
2302 | for(;;) { |
3427 | libname[0] = '\0'; |
2303 | if (t == LD_TOK_EOF) { |
3428 | if (t == LD_TOK_EOF) { |
- | 3429 | tcc_error_noabort("unexpected end of file"); |
|
2304 | error_noabort("unexpected end of file"); |
3430 | ret = -1; |
2305 | return -1; |
3431 | goto lib_parse_error; |
- | 3432 | } else if (t == ')') { |
|
- | 3433 | break; |
|
- | 3434 | } else if (t == '-') { |
|
- | 3435 | t = ld_next(s1, filename, sizeof(filename)); |
|
- | 3436 | if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { |
|
- | 3437 | tcc_error_noabort("library name expected"); |
|
- | 3438 | ret = -1; |
|
- | 3439 | goto lib_parse_error; |
|
- | 3440 | } |
|
- | 3441 | pstrcpy(libname, sizeof libname, &filename[1]); |
|
- | 3442 | if (s1->static_link) { |
|
- | 3443 | snprintf(filename, sizeof filename, "lib%s.a", libname); |
|
- | 3444 | } else { |
|
2306 | } else if (t == ')') { |
3445 | snprintf(filename, sizeof filename, "lib%s.so", libname); |
2307 | break; |
3446 | } |
- | 3447 | } else if (t != LD_TOK_NAME) { |
|
- | 3448 | tcc_error_noabort("filename expected"); |
|
- | 3449 | ret = -1; |
|
- | 3450 | goto lib_parse_error; |
|
- | 3451 | } |
|
- | 3452 | if (!strcmp(filename, "AS_NEEDED")) { |
|
- | 3453 | ret = ld_add_file_list(s1, cmd, 1); |
|
- | 3454 | if (ret) |
|
- | 3455 | goto lib_parse_error; |
|
- | 3456 | } else { |
|
- | 3457 | /* TODO: Implement AS_NEEDED support. Ignore it for now */ |
|
2308 | } else if (t != LD_TOK_NAME) { |
3458 | if (!as_needed) { |
- | 3459 | ret = ld_add_file(s1, filename); |
|
- | 3460 | if (ret) |
|
- | 3461 | goto lib_parse_error; |
|
- | 3462 | if (group) { |
|
- | 3463 | /* Add the filename *and* the libname to avoid future conversions */ |
|
- | 3464 | dynarray_add((void ***) &libs, &nblibs, tcc_strdup(filename)); |
|
- | 3465 | if (libname[0] != '\0') |
|
- | 3466 | dynarray_add((void ***) &libs, &nblibs, tcc_strdup(libname)); |
|
2309 | error_noabort("filename expected"); |
3467 | } |
2310 | return -1; |
- | |
2311 | } |
3468 | } |
2312 | tcc_add_file(s1, filename); |
3469 | } |
2313 | t = ld_next(s1, filename, sizeof(filename)); |
3470 | t = ld_next(s1, filename, sizeof(filename)); |
2314 | if (t == ',') { |
3471 | if (t == ',') { |
2315 | t = ld_next(s1, filename, sizeof(filename)); |
3472 | t = ld_next(s1, filename, sizeof(filename)); |
- | 3473 | } |
|
- | 3474 | } |
|
- | 3475 | if (group && !as_needed) { |
|
- | 3476 | while (new_undef_syms()) { |
|
- | 3477 | int i; |
|
- | 3478 | ||
- | 3479 | for (i = 0; i < nblibs; i ++) |
|
- | 3480 | ld_add_file(s1, libs[i]); |
|
- | 3481 | } |
|
- | 3482 | } |
|
- | 3483 | lib_parse_error: |
|
- | 3484 | dynarray_reset(&libs, &nblibs); |
|
- | 3485 | return ret; |
|
- | 3486 | } |
|
- | 3487 | ||
- | 3488 | /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
|
- | 3489 | files */ |
|
- | 3490 | ST_FUNC int tcc_load_ldscript(TCCState *s1) |
|
- | 3491 | { |
|
- | 3492 | char cmd[64]; |
|
- | 3493 | char filename[1024]; |
|
- | 3494 | int t, ret; |
|
- | 3495 | ||
- | 3496 | ch = handle_eob(); |
|
- | 3497 | for(;;) { |
|
- | 3498 | t = ld_next(s1, cmd, sizeof(cmd)); |
|
- | 3499 | if (t == LD_TOK_EOF) |
|
- | 3500 | return 0; |
|
- | 3501 | else if (t != LD_TOK_NAME) |
|
- | 3502 | return -1; |
|
- | 3503 | if (!strcmp(cmd, "INPUT") || |
|
- | 3504 | !strcmp(cmd, "GROUP")) { |
|
- | 3505 | ret = ld_add_file_list(s1, cmd, 0); |
|
2316 | } |
3506 | if (ret) |
2317 | } |
3507 | return ret; |
2318 | } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
3508 | } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
2319 | !strcmp(cmd, "TARGET")) { |
3509 | !strcmp(cmd, "TARGET")) { |
2320 | /* ignore some commands */ |
3510 | /* ignore some commands */ |
2321 | t = ld_next(s1, cmd, sizeof(cmd)); |
3511 | t = ld_next(s1, cmd, sizeof(cmd)); |
2322 | if (t != '(') |
3512 | if (t != '(') |
2323 | expect("("); |
3513 | expect("("); |
2324 | for(;;) { |
3514 | for(;;) { |
2325 | t = ld_next(s1, filename, sizeof(filename)); |
3515 | t = ld_next(s1, filename, sizeof(filename)); |
2326 | if (t == LD_TOK_EOF) { |
3516 | if (t == LD_TOK_EOF) { |
2327 | error_noabort("unexpected end of file"); |
3517 | tcc_error_noabort("unexpected end of file"); |
2328 | return -1; |
3518 | return -1; |
2329 | } else if (t == ')') { |
3519 | } else if (t == ')') { |
2330 | break; |
3520 | break; |
Line 2334... | Line 3524... | ||
2334 | return -1; |
3524 | return -1; |
2335 | } |
3525 | } |
2336 | } |
3526 | } |
2337 | return 0; |
3527 | return 0; |
2338 | }>=>=>=>>>>>>>>>>>>><>><>><>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><>><>><>>>><>><>><>><>><>>>>>>>>>>>>><> |
3528 | } |
- | 3529 | #endif /* !TCC_TARGET_PE */>>=>=>=>>>>>>>>>>>>><>><>><>>>>>>>>>>>>->>>>>>>>>>>>>>><>><>><>><>><>>><>><>><>><>><>>>>>>>>=><=>><>>>>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>><>>>><>><>><>><>><>><>><>><>>=><=>>>>>>>>>><> |