1 | /* |
2 | * ELF file handling for TCC |
3 | * |
4 | * Copyright (c) 2001-2004 Fabrice Bellard |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
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 |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ |
20 | |
21 | #include "tcc.h" |
22 | |
23 | /* Define this to get some debug output during relocation processing. */ |
24 | #undef DEBUG_RELOC |
25 | |
26 | /********************************************************/ |
27 | /* global variables */ |
28 | |
29 | /* elf version information */ |
30 | struct sym_version { |
31 | char *lib; |
32 | char *version; |
33 | int out_index; |
34 | int prev_same_lib; |
35 | }; |
36 | |
37 | #define nb_sym_versions s1->nb_sym_versions |
38 | #define sym_versions s1->sym_versions |
39 | #define nb_sym_to_version s1->nb_sym_to_version |
40 | #define sym_to_version s1->sym_to_version |
41 | #define dt_verneednum s1->dt_verneednum |
42 | #define versym_section s1->versym_section |
43 | #define verneed_section s1->verneed_section |
44 | |
45 | /* special flag to indicate that the section should not be linked to the other ones */ |
46 | #define SHF_PRIVATE 0x80000000 |
47 | /* section is dynsymtab_section */ |
48 | #define SHF_DYNSYM 0x40000000 |
49 | |
50 | /* ------------------------------------------------------------------------- */ |
51 | |
52 | ST_FUNC void tccelf_new(TCCState *s) |
53 | { |
54 | TCCState *s1 = s; |
55 | /* no section zero */ |
56 | dynarray_add(&s->sections, &s->nb_sections, NULL); |
57 | |
58 | /* create standard sections */ |
59 | text_section = new_section(s, ".text" , SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR); |
60 | data_section = new_section(s, ".data" , SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
61 | bss_section = new_section(s, ".bss" , SHT_NOBITS, SHF_ALLOC | SHF_WRITE); |
62 | common_section = new_section(s, ".common" , SHT_NOBITS, SHF_PRIVATE); |
63 | common_section->sh_num = SHN_COMMON; |
64 | |
65 | /* symbols are always generated for linking stage */ |
66 | symtab_section = new_symtab(s, ".symtab" , SHT_SYMTAB, 0, |
67 | ".strtab" , |
68 | ".hashtab" , SHF_PRIVATE); |
69 | s->symtab = symtab_section; |
70 | |
71 | /* private symbol table for dynamic symbols */ |
72 | s->dynsymtab_section = new_symtab(s, ".dynsymtab" , SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM, |
73 | ".dynstrtab" , |
74 | ".dynhashtab" , SHF_PRIVATE); |
75 | get_sym_attr(s, 0, 1); |
76 | } |
77 | |
78 | #ifdef CONFIG_TCC_BCHECK |
79 | ST_FUNC void tccelf_bounds_new(TCCState *s) |
80 | { |
81 | TCCState *s1 = s; |
82 | /* create bounds sections */ |
83 | bounds_section = new_section(s, ".bounds" , |
84 | SHT_PROGBITS, SHF_ALLOC); |
85 | lbounds_section = new_section(s, ".lbounds" , |
86 | SHT_PROGBITS, SHF_ALLOC); |
87 | } |
88 | #endif |
89 | |
90 | ST_FUNC void tccelf_stab_new(TCCState *s) |
91 | { |
92 | TCCState *s1 = s; |
93 | int shf = 0; |
94 | #ifdef CONFIG_TCC_BACKTRACE |
95 | /* include stab info with standalone backtrace support */ |
96 | if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY) |
97 | shf = SHF_ALLOC; |
98 | #endif |
99 | stab_section = new_section(s, ".stab" , SHT_PROGBITS, shf); |
100 | stab_section->sh_entsize = sizeof(Stab_Sym); |
101 | stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value; |
102 | stab_section->link = new_section(s, ".stabstr" , SHT_STRTAB, shf); |
103 | /* put first entry */ |
104 | put_stabs(s, "" , 0, 0, 0, 0); |
105 | } |
106 | |
107 | static void free_section(Section *s) |
108 | { |
109 | tcc_free(s->data); |
110 | } |
111 | |
112 | ST_FUNC void tccelf_delete(TCCState *s1) |
113 | { |
114 | int i; |
115 | |
116 | #ifndef ELF_OBJ_ONLY |
117 | /* free symbol versions */ |
118 | for (i = 0; i < nb_sym_versions; i++) { |
119 | tcc_free(sym_versions[i].version); |
120 | tcc_free(sym_versions[i].lib); |
121 | } |
122 | tcc_free(sym_versions); |
123 | tcc_free(sym_to_version); |
124 | #endif |
125 | |
126 | /* free all sections */ |
127 | for(i = 1; i < s1->nb_sections; i++) |
128 | free_section(s1->sections[i]); |
129 | dynarray_reset(&s1->sections, &s1->nb_sections); |
130 | |
131 | for(i = 0; i < s1->nb_priv_sections; i++) |
132 | free_section(s1->priv_sections[i]); |
133 | dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections); |
134 | |
135 | /* free any loaded DLLs */ |
136 | #ifdef TCC_IS_NATIVE |
137 | for ( i = 0; i < s1->nb_loaded_dlls; i++) { |
138 | DLLReference *ref = s1->loaded_dlls[i]; |
139 | if ( ref->handle ) |
140 | # ifdef _WIN32 |
141 | FreeLibrary((HMODULE)ref->handle); |
142 | # else |
143 | dlclose(ref->handle); |
144 | # endif |
145 | } |
146 | #endif |
147 | /* free loaded dlls array */ |
148 | dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls); |
149 | tcc_free(s1->sym_attrs); |
150 | |
151 | symtab_section = NULL; /* for tccrun.c:rt_printline() */ |
152 | } |
153 | |
154 | /* save section data state */ |
155 | ST_FUNC void tccelf_begin_file(TCCState *s1) |
156 | { |
157 | Section *s; int i; |
158 | for (i = 1; i < s1->nb_sections; i++) { |
159 | s = s1->sections[i]; |
160 | s->sh_offset = s->data_offset; |
161 | } |
162 | /* disable symbol hashing during compilation */ |
163 | s = s1->symtab, s->reloc = s->hash, s->hash = NULL; |
164 | #if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE |
165 | s1->uw_sym = 0; |
166 | #endif |
167 | } |
168 | |
169 | /* At the end of compilation, convert any UNDEF syms to global, and merge |
170 | with previously existing symbols */ |
171 | ST_FUNC void tccelf_end_file(TCCState *s1) |
172 | { |
173 | Section *s = s1->symtab; |
174 | int first_sym, nb_syms, *tr, i; |
175 | |
176 | first_sym = s->sh_offset / sizeof (ElfSym); |
177 | nb_syms = s->data_offset / sizeof (ElfSym) - first_sym; |
178 | s->data_offset = s->sh_offset; |
179 | s->link->data_offset = s->link->sh_offset; |
180 | s->hash = s->reloc, s->reloc = NULL; |
181 | tr = tcc_mallocz(nb_syms * sizeof *tr); |
182 | |
183 | for (i = 0; i < nb_syms; ++i) { |
184 | ElfSym *sym = (ElfSym*)s->data + first_sym + i; |
185 | if (sym->st_shndx == SHN_UNDEF |
186 | && ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) |
187 | sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info)); |
188 | tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info, |
189 | sym->st_other, sym->st_shndx, (char*)s->link->data + sym->st_name); |
190 | } |
191 | /* now update relocations */ |
192 | for (i = 1; i < s1->nb_sections; i++) { |
193 | Section *sr = s1->sections[i]; |
194 | if (sr->sh_type == SHT_RELX && sr->link == s) { |
195 | ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset); |
196 | ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset); |
197 | for (; rel < rel_end; ++rel) { |
198 | int n = ELFW(R_SYM)(rel->r_info) - first_sym; |
199 | //if (n < 0) tcc_error("internal: invalid symbol index in relocation"); |
200 | rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info)); |
201 | } |
202 | } |
203 | } |
204 | tcc_free(tr); |
205 | |
206 | /* record text/data/bss output for -bench info */ |
207 | for (i = 0; i < 3; ++i) { |
208 | s = s1->sections[i + 1]; |
209 | s1->total_output[i] += s->data_offset - s->sh_offset; |
210 | } |
211 | } |
212 | |
213 | ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags) |
214 | { |
215 | Section *sec; |
216 | |
217 | sec = tcc_mallocz(sizeof(Section) + strlen(name)); |
218 | sec->s1 = s1; |
219 | strcpy(sec->name, name); |
220 | sec->sh_type = sh_type; |
221 | sec->sh_flags = sh_flags; |
222 | switch(sh_type) { |
223 | case SHT_GNU_versym: |
224 | sec->sh_addralign = 2; |
225 | break; |
226 | case SHT_HASH: |
227 | case SHT_REL: |
228 | case SHT_RELA: |
229 | case SHT_DYNSYM: |
230 | case SHT_SYMTAB: |
231 | case SHT_DYNAMIC: |
232 | case SHT_GNU_verneed: |
233 | case SHT_GNU_verdef: |
234 | sec->sh_addralign = PTR_SIZE; |
235 | break; |
236 | case SHT_STRTAB: |
237 | sec->sh_addralign = 1; |
238 | break; |
239 | default: |
240 | sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */ |
241 | break; |
242 | } |
243 | |
244 | if (sh_flags & SHF_PRIVATE) { |
245 | dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec); |
246 | } else { |
247 | sec->sh_num = s1->nb_sections; |
248 | dynarray_add(&s1->sections, &s1->nb_sections, sec); |
249 | } |
250 | |
251 | return sec; |
252 | } |
253 | |
254 | ST_FUNC Section *new_symtab(TCCState *s1, |
255 | const char *symtab_name, int sh_type, int sh_flags, |
256 | const char *strtab_name, |
257 | const char *hash_name, int hash_sh_flags) |
258 | { |
259 | Section *symtab, *strtab, *hash; |
260 | int *ptr, nb_buckets; |
261 | |
262 | symtab = new_section(s1, symtab_name, sh_type, sh_flags); |
263 | symtab->sh_entsize = sizeof(ElfW(Sym)); |
264 | strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); |
265 | put_elf_str(strtab, "" ); |
266 | symtab->link = strtab; |
267 | put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); |
268 | |
269 | nb_buckets = 1; |
270 | |
271 | hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); |
272 | hash->sh_entsize = sizeof(int); |
273 | symtab->hash = hash; |
274 | hash->link = symtab; |
275 | |
276 | ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); |
277 | ptr[0] = nb_buckets; |
278 | ptr[1] = 1; |
279 | memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); |
280 | return symtab; |
281 | } |
282 | |
283 | /* realloc section and set its content to zero */ |
284 | ST_FUNC void section_realloc(Section *sec, unsigned long new_size) |
285 | { |
286 | unsigned long size; |
287 | unsigned char *data; |
288 | |
289 | size = sec->data_allocated; |
290 | if (size == 0) |
291 | size = 1; |
292 | while (size < new_size) |
293 | size = size * 2; |
294 | data = tcc_realloc(sec->data, size); |
295 | memset(data + sec->data_allocated, 0, size - sec->data_allocated); |
296 | sec->data = data; |
297 | sec->data_allocated = size; |
298 | } |
299 | |
300 | /* reserve at least 'size' bytes aligned per 'align' in section |
301 | 'sec' from current offset, and return the aligned offset */ |
302 | ST_FUNC size_t section_add(Section *sec, addr_t size, int align) |
303 | { |
304 | size_t offset, offset1; |
305 | |
306 | offset = (sec->data_offset + align - 1) & -align; |
307 | offset1 = offset + size; |
308 | if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated) |
309 | section_realloc(sec, offset1); |
310 | sec->data_offset = offset1; |
311 | if (align > sec->sh_addralign) |
312 | sec->sh_addralign = align; |
313 | return offset; |
314 | } |
315 | |
316 | /* reserve at least 'size' bytes in section 'sec' from |
317 | sec->data_offset. */ |
318 | ST_FUNC void *section_ptr_add(Section *sec, addr_t size) |
319 | { |
320 | size_t offset = section_add(sec, size, 1); |
321 | return sec->data + offset; |
322 | } |
323 | |
324 | #ifndef ELF_OBJ_ONLY |
325 | /* reserve at least 'size' bytes from section start */ |
326 | static void section_reserve(Section *sec, unsigned long size) |
327 | { |
328 | if (size > sec->data_allocated) |
329 | section_realloc(sec, size); |
330 | if (size > sec->data_offset) |
331 | sec->data_offset = size; |
332 | } |
333 | #endif |
334 | |
335 | static Section *find_section_create (TCCState *s1, const char *name, int create) |
336 | { |
337 | Section *sec; |
338 | int i; |
339 | for(i = 1; i < s1->nb_sections; i++) { |
340 | sec = s1->sections[i]; |
341 | if (!strcmp(name, sec->name)) |
342 | return sec; |
343 | } |
344 | /* sections are created as PROGBITS */ |
345 | return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL; |
346 | } |
347 | |
348 | /* return a reference to a section, and create it if it does not |
349 | exists */ |
350 | ST_FUNC Section *find_section(TCCState *s1, const char *name) |
351 | { |
352 | return find_section_create (s1, name, 1); |
353 | } |
354 | |
355 | /* ------------------------------------------------------------------------- */ |
356 | |
357 | ST_FUNC int put_elf_str(Section *s, const char *sym) |
358 | { |
359 | int offset, len; |
360 | char *ptr; |
361 | |
362 | len = strlen(sym) + 1; |
363 | offset = s->data_offset; |
364 | ptr = section_ptr_add(s, len); |
365 | memmove(ptr, sym, len); |
366 | return offset; |
367 | } |
368 | |
369 | /* elf symbol hashing function */ |
370 | static unsigned long elf_hash(const unsigned char *name) |
371 | { |
372 | unsigned long h = 0, g; |
373 | |
374 | while (*name) { |
375 | h = (h << 4) + *name++; |
376 | g = h & 0xf0000000; |
377 | if (g) |
378 | h ^= g >> 24; |
379 | h &= ~g; |
380 | } |
381 | return h; |
382 | } |
383 | |
384 | /* rebuild hash table of section s */ |
385 | /* NOTE: we do factorize the hash table code to go faster */ |
386 | static void rebuild_hash(Section *s, unsigned int nb_buckets) |
387 | { |
388 | ElfW(Sym) *sym; |
389 | int *ptr, *hash, nb_syms, sym_index, h; |
390 | unsigned char *strtab; |
391 | |
392 | strtab = s->link->data; |
393 | nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
394 | |
395 | if (!nb_buckets) |
396 | nb_buckets = ((int*)s->hash->data)[0]; |
397 | |
398 | s->hash->data_offset = 0; |
399 | ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); |
400 | ptr[0] = nb_buckets; |
401 | ptr[1] = nb_syms; |
402 | ptr += 2; |
403 | hash = ptr; |
404 | memset(hash, 0, (nb_buckets + 1) * sizeof(int)); |
405 | ptr += nb_buckets + 1; |
406 | |
407 | sym = (ElfW(Sym) *)s->data + 1; |
408 | for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
409 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
410 | h = elf_hash(strtab + sym->st_name) % nb_buckets; |
411 | *ptr = hash[h]; |
412 | hash[h] = sym_index; |
413 | } else { |
414 | *ptr = 0; |
415 | } |
416 | ptr++; |
417 | sym++; |
418 | } |
419 | } |
420 | |
421 | /* return the symbol number */ |
422 | ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, |
423 | int info, int other, int shndx, const char *name) |
424 | { |
425 | int name_offset, sym_index; |
426 | int nbuckets, h; |
427 | ElfW(Sym) *sym; |
428 | Section *hs; |
429 | |
430 | sym = section_ptr_add(s, sizeof(ElfW(Sym))); |
431 | if (name && name[0]) |
432 | name_offset = put_elf_str(s->link, name); |
433 | else |
434 | name_offset = 0; |
435 | /* XXX: endianness */ |
436 | sym->st_name = name_offset; |
437 | sym->st_value = value; |
438 | sym->st_size = size; |
439 | sym->st_info = info; |
440 | sym->st_other = other; |
441 | sym->st_shndx = shndx; |
442 | sym_index = sym - (ElfW(Sym) *)s->data; |
443 | hs = s->hash; |
444 | if (hs) { |
445 | int *ptr, *base; |
446 | ptr = section_ptr_add(hs, sizeof(int)); |
447 | base = (int *)hs->data; |
448 | /* only add global or weak symbols. */ |
449 | if (ELFW(ST_BIND)(info) != STB_LOCAL) { |
450 | /* add another hashing entry */ |
451 | nbuckets = base[0]; |
452 | h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets; |
453 | *ptr = base[2 + h]; |
454 | base[2 + h] = sym_index; |
455 | base[1]++; |
456 | /* we resize the hash table */ |
457 | hs->nb_hashed_syms++; |
458 | if (hs->nb_hashed_syms > 2 * nbuckets) { |
459 | rebuild_hash(s, 2 * nbuckets); |
460 | } |
461 | } else { |
462 | *ptr = 0; |
463 | base[1]++; |
464 | } |
465 | } |
466 | return sym_index; |
467 | } |
468 | |
469 | ST_FUNC int find_elf_sym(Section *s, const char *name) |
470 | { |
471 | ElfW(Sym) *sym; |
472 | Section *hs; |
473 | int nbuckets, sym_index, h; |
474 | const char *name1; |
475 | |
476 | hs = s->hash; |
477 | if (!hs) |
478 | return 0; |
479 | nbuckets = ((int *)hs->data)[0]; |
480 | h = elf_hash((unsigned char *) name) % nbuckets; |
481 | sym_index = ((int *)hs->data)[2 + h]; |
482 | while (sym_index != 0) { |
483 | sym = &((ElfW(Sym) *)s->data)[sym_index]; |
484 | name1 = (char *) s->link->data + sym->st_name; |
485 | if (!strcmp(name, name1)) |
486 | return sym_index; |
487 | sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; |
488 | } |
489 | return 0; |
490 | } |
491 | |
492 | /* return elf symbol value, signal error if 'err' is nonzero, decorate |
493 | name if FORC */ |
494 | ST_FUNC addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc) |
495 | { |
496 | int sym_index; |
497 | ElfW(Sym) *sym; |
498 | char buf[256]; |
499 | if (forc && s1->leading_underscore |
500 | #ifdef TCC_TARGET_PE |
501 | /* win32-32bit stdcall symbols always have _ already */ |
502 | && !strchr(name, '@') |
503 | #endif |
504 | ) { |
505 | buf[0] = '_'; |
506 | pstrcpy(buf + 1, sizeof(buf) - 1, name); |
507 | name = buf; |
508 | } |
509 | sym_index = find_elf_sym(s1->symtab, name); |
510 | sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index]; |
511 | if (!sym_index || sym->st_shndx == SHN_UNDEF) { |
512 | if (err) |
513 | tcc_error("%s not defined" , name); |
514 | return (addr_t)-1; |
515 | } |
516 | return sym->st_value; |
517 | } |
518 | |
519 | /* return elf symbol value */ |
520 | LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) |
521 | { |
522 | addr_t addr = get_sym_addr(s, name, 0, 1); |
523 | return addr == -1 ? NULL : (void*)(uintptr_t)addr; |
524 | } |
525 | |
526 | /* list elf symbol names and values */ |
527 | ST_FUNC void list_elf_symbols(TCCState *s, void *ctx, |
528 | void (*symbol_cb)(void *ctx, const char *name, const void *val)) |
529 | { |
530 | ElfW(Sym) *sym; |
531 | Section *symtab; |
532 | int sym_index, end_sym; |
533 | const char *name; |
534 | unsigned char sym_vis, sym_bind; |
535 | |
536 | symtab = s->symtab; |
537 | end_sym = symtab->data_offset / sizeof (ElfSym); |
538 | for (sym_index = 0; sym_index < end_sym; ++sym_index) { |
539 | sym = &((ElfW(Sym) *)symtab->data)[sym_index]; |
540 | if (sym->st_value) { |
541 | name = (char *) symtab->link->data + sym->st_name; |
542 | sym_bind = ELFW(ST_BIND)(sym->st_info); |
543 | sym_vis = ELFW(ST_VISIBILITY)(sym->st_other); |
544 | if (sym_bind == STB_GLOBAL && sym_vis == STV_DEFAULT) |
545 | symbol_cb(ctx, name, (void*)(uintptr_t)sym->st_value); |
546 | } |
547 | } |
548 | } |
549 | |
550 | /* list elf symbol names and values */ |
551 | LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx, |
552 | void (*symbol_cb)(void *ctx, const char *name, const void *val)) |
553 | { |
554 | list_elf_symbols(s, ctx, symbol_cb); |
555 | } |
556 | |
557 | #ifndef ELF_OBJ_ONLY |
558 | static void |
559 | version_add (TCCState *s1) |
560 | { |
561 | int i; |
562 | ElfW(Sym) *sym; |
563 | ElfW(Verneed) *vn = NULL; |
564 | Section *symtab; |
565 | int sym_index, end_sym, nb_versions = 2, nb_entries = 0; |
566 | ElfW(Half) *versym; |
567 | const char *name; |
568 | |
569 | if (0 == nb_sym_versions) |
570 | return; |
571 | versym_section = new_section(s1, ".gnu.version" , SHT_GNU_versym, SHF_ALLOC); |
572 | versym_section->sh_entsize = sizeof(ElfW(Half)); |
573 | versym_section->link = s1->dynsym; |
574 | |
575 | /* add needed symbols */ |
576 | symtab = s1->dynsym; |
577 | end_sym = symtab->data_offset / sizeof (ElfSym); |
578 | versym = section_ptr_add(versym_section, end_sym * sizeof(ElfW(Half))); |
579 | for (sym_index = 0; sym_index < end_sym; ++sym_index) { |
580 | int dllindex, verndx; |
581 | sym = &((ElfW(Sym) *)symtab->data)[sym_index]; |
582 | name = (char *) symtab->link->data + sym->st_name; |
583 | dllindex = find_elf_sym(s1->dynsymtab_section, name); |
584 | verndx = (dllindex && dllindex < nb_sym_to_version) |
585 | ? sym_to_version[dllindex] : -1; |
586 | if (verndx >= 0) { |
587 | if (!sym_versions[verndx].out_index) |
588 | sym_versions[verndx].out_index = nb_versions++; |
589 | versym[sym_index] = sym_versions[verndx].out_index; |
590 | } else |
591 | versym[sym_index] = 0; |
592 | } |
593 | /* generate verneed section, but not when it will be empty. Some |
594 | dynamic linkers look at their contents even when DTVERNEEDNUM and |
595 | section size is zero. */ |
596 | if (nb_versions > 2) { |
597 | verneed_section = new_section(s1, ".gnu.version_r" , |
598 | SHT_GNU_verneed, SHF_ALLOC); |
599 | verneed_section->link = s1->dynsym->link; |
600 | for (i = nb_sym_versions; i-- > 0;) { |
601 | struct sym_version *sv = &sym_versions[i]; |
602 | int n_same_libs = 0, prev; |
603 | size_t vnofs; |
604 | ElfW(Vernaux) *vna = 0; |
605 | if (sv->out_index < 1) |
606 | continue; |
607 | vnofs = section_add(verneed_section, sizeof(*vn), 1); |
608 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); |
609 | vn->vn_version = 1; |
610 | vn->vn_file = put_elf_str(verneed_section->link, sv->lib); |
611 | vn->vn_aux = sizeof (*vn); |
612 | do { |
613 | prev = sv->prev_same_lib; |
614 | if (sv->out_index > 0) { |
615 | vna = section_ptr_add(verneed_section, sizeof(*vna)); |
616 | vna->vna_hash = elf_hash ((const unsigned char *)sv->version); |
617 | vna->vna_flags = 0; |
618 | vna->vna_other = sv->out_index; |
619 | sv->out_index = -2; |
620 | vna->vna_name = put_elf_str(verneed_section->link, sv->version); |
621 | vna->vna_next = sizeof (*vna); |
622 | n_same_libs++; |
623 | } |
624 | if (prev >= 0) |
625 | sv = &sym_versions[prev]; |
626 | } while(prev >= 0); |
627 | vna->vna_next = 0; |
628 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); |
629 | vn->vn_cnt = n_same_libs; |
630 | vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna); |
631 | nb_entries++; |
632 | } |
633 | if (vn) |
634 | vn->vn_next = 0; |
635 | verneed_section->sh_info = nb_entries; |
636 | } |
637 | dt_verneednum = nb_entries; |
638 | } |
639 | #endif |
640 | |
641 | /* add an elf symbol : check if it is already defined and patch |
642 | it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ |
643 | ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size, |
644 | int info, int other, int shndx, const char *name) |
645 | { |
646 | TCCState *s1 = s->s1; |
647 | ElfW(Sym) *esym; |
648 | int sym_bind, sym_index, sym_type, esym_bind; |
649 | unsigned char sym_vis, esym_vis, new_vis; |
650 | |
651 | sym_bind = ELFW(ST_BIND)(info); |
652 | sym_type = ELFW(ST_TYPE)(info); |
653 | sym_vis = ELFW(ST_VISIBILITY)(other); |
654 | |
655 | if (sym_bind != STB_LOCAL) { |
656 | /* we search global or weak symbols */ |
657 | sym_index = find_elf_sym(s, name); |
658 | if (!sym_index) |
659 | goto do_def; |
660 | esym = &((ElfW(Sym) *)s->data)[sym_index]; |
661 | if (esym->st_value == value && esym->st_size == size && esym->st_info == info |
662 | && esym->st_other == other && esym->st_shndx == shndx) |
663 | return sym_index; |
664 | if (esym->st_shndx != SHN_UNDEF) { |
665 | esym_bind = ELFW(ST_BIND)(esym->st_info); |
666 | /* propagate the most constraining visibility */ |
667 | /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */ |
668 | esym_vis = ELFW(ST_VISIBILITY)(esym->st_other); |
669 | if (esym_vis == STV_DEFAULT) { |
670 | new_vis = sym_vis; |
671 | } else if (sym_vis == STV_DEFAULT) { |
672 | new_vis = esym_vis; |
673 | } else { |
674 | new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; |
675 | } |
676 | esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
677 | | new_vis; |
678 | other = esym->st_other; /* in case we have to patch esym */ |
679 | if (shndx == SHN_UNDEF) { |
680 | /* ignore adding of undefined symbol if the |
681 | corresponding symbol is already defined */ |
682 | } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { |
683 | /* global overrides weak, so patch */ |
684 | goto do_patch; |
685 | } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { |
686 | /* weak is ignored if already global */ |
687 | } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { |
688 | /* keep first-found weak definition, ignore subsequents */ |
689 | } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { |
690 | /* ignore hidden symbols after */ |
691 | } else if ((esym->st_shndx == SHN_COMMON |
692 | || esym->st_shndx == bss_section->sh_num) |
693 | && (shndx < SHN_LORESERVE |
694 | && shndx != bss_section->sh_num)) { |
695 | /* data symbol gets precedence over common/bss */ |
696 | goto do_patch; |
697 | } else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) { |
698 | /* data symbol keeps precedence over common/bss */ |
699 | } else if (s->sh_flags & SHF_DYNSYM) { |
700 | /* we accept that two DLL define the same symbol */ |
701 | } else if (esym->st_other & ST_ASM_SET) { |
702 | /* If the existing symbol came from an asm .set |
703 | we can override. */ |
704 | goto do_patch; |
705 | } else { |
706 | #if 0 |
707 | printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n" , |
708 | sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis); |
709 | #endif |
710 | tcc_error_noabort("'%s' defined twice" , name); |
711 | } |
712 | } else { |
713 | do_patch: |
714 | esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); |
715 | esym->st_shndx = shndx; |
716 | s1->new_undef_sym = 1; |
717 | esym->st_value = value; |
718 | esym->st_size = size; |
719 | esym->st_other = other; |
720 | } |
721 | } else { |
722 | do_def: |
723 | sym_index = put_elf_sym(s, value, size, |
724 | ELFW(ST_INFO)(sym_bind, sym_type), other, |
725 | shndx, name); |
726 | } |
727 | return sym_index; |
728 | } |
729 | |
730 | /* put relocation */ |
731 | ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, |
732 | int type, int symbol, addr_t addend) |
733 | { |
734 | TCCState *s1 = s->s1; |
735 | char buf[256]; |
736 | Section *sr; |
737 | ElfW_Rel *rel; |
738 | |
739 | sr = s->reloc; |
740 | if (!sr) { |
741 | /* if no relocation section, create it */ |
742 | snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); |
743 | /* if the symtab is allocated, then we consider the relocation |
744 | are also */ |
745 | sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags); |
746 | sr->sh_entsize = sizeof(ElfW_Rel); |
747 | sr->link = symtab; |
748 | sr->sh_info = s->sh_num; |
749 | s->reloc = sr; |
750 | } |
751 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
752 | rel->r_offset = offset; |
753 | rel->r_info = ELFW(R_INFO)(symbol, type); |
754 | #if SHT_RELX == SHT_RELA |
755 | rel->r_addend = addend; |
756 | #endif |
757 | if (SHT_RELX != SHT_RELA && addend) |
758 | tcc_error("non-zero addend on REL architecture" ); |
759 | } |
760 | |
761 | ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
762 | int type, int symbol) |
763 | { |
764 | put_elf_reloca(symtab, s, offset, type, symbol, 0); |
765 | } |
766 | |
767 | /* put stab debug information */ |
768 | ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc, |
769 | unsigned long value) |
770 | { |
771 | Stab_Sym *sym; |
772 | |
773 | unsigned offset; |
774 | if (type == N_SLINE |
775 | && (offset = stab_section->data_offset) |
776 | && (sym = (Stab_Sym*)(stab_section->data + offset) - 1) |
777 | && sym->n_type == type |
778 | && sym->n_value == value) { |
779 | /* just update line_number in previous entry */ |
780 | sym->n_desc = desc; |
781 | return; |
782 | } |
783 | |
784 | sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); |
785 | if (str) { |
786 | sym->n_strx = put_elf_str(stab_section->link, str); |
787 | } else { |
788 | sym->n_strx = 0; |
789 | } |
790 | sym->n_type = type; |
791 | sym->n_other = other; |
792 | sym->n_desc = desc; |
793 | sym->n_value = value; |
794 | } |
795 | |
796 | ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc, |
797 | unsigned long value, Section *sec, int sym_index) |
798 | { |
799 | put_elf_reloc(symtab_section, stab_section, |
800 | stab_section->data_offset + 8, |
801 | sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32, |
802 | sym_index); |
803 | put_stabs(s1, str, type, other, desc, value); |
804 | } |
805 | |
806 | ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value) |
807 | { |
808 | put_stabs(s1, NULL, type, other, desc, value); |
809 | } |
810 | |
811 | ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc) |
812 | { |
813 | int n; |
814 | struct sym_attr *tab; |
815 | |
816 | if (index >= s1->nb_sym_attrs) { |
817 | if (!alloc) |
818 | return s1->sym_attrs; |
819 | /* find immediately bigger power of 2 and reallocate array */ |
820 | n = 1; |
821 | while (index >= n) |
822 | n *= 2; |
823 | tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs)); |
824 | s1->sym_attrs = tab; |
825 | memset(s1->sym_attrs + s1->nb_sym_attrs, 0, |
826 | (n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs)); |
827 | s1->nb_sym_attrs = n; |
828 | } |
829 | return &s1->sym_attrs[index]; |
830 | } |
831 | |
832 | /* In an ELF file symbol table, the local symbols must appear below |
833 | the global and weak ones. Since TCC cannot sort it while generating |
834 | the code, we must do it after. All the relocation tables are also |
835 | modified to take into account the symbol table sorting */ |
836 | static void sort_syms(TCCState *s1, Section *s) |
837 | { |
838 | int *old_to_new_syms; |
839 | ElfW(Sym) *new_syms; |
840 | int nb_syms, i; |
841 | ElfW(Sym) *p, *q; |
842 | ElfW_Rel *rel; |
843 | Section *sr; |
844 | int type, sym_index; |
845 | |
846 | nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
847 | new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); |
848 | old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); |
849 | |
850 | /* first pass for local symbols */ |
851 | p = (ElfW(Sym) *)s->data; |
852 | q = new_syms; |
853 | for(i = 0; i < nb_syms; i++) { |
854 | if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { |
855 | old_to_new_syms[i] = q - new_syms; |
856 | *q++ = *p; |
857 | } |
858 | p++; |
859 | } |
860 | /* save the number of local symbols in section header */ |
861 | if( s->sh_size ) /* this 'if' makes IDA happy */ |
862 | s->sh_info = q - new_syms; |
863 | |
864 | /* then second pass for non local symbols */ |
865 | p = (ElfW(Sym) *)s->data; |
866 | for(i = 0; i < nb_syms; i++) { |
867 | if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { |
868 | old_to_new_syms[i] = q - new_syms; |
869 | *q++ = *p; |
870 | } |
871 | p++; |
872 | } |
873 | |
874 | /* we copy the new symbols to the old */ |
875 | memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); |
876 | tcc_free(new_syms); |
877 | |
878 | /* now we modify all the relocations */ |
879 | for(i = 1; i < s1->nb_sections; i++) { |
880 | sr = s1->sections[i]; |
881 | if (sr->sh_type == SHT_RELX && sr->link == s) { |
882 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
883 | sym_index = ELFW(R_SYM)(rel->r_info); |
884 | type = ELFW(R_TYPE)(rel->r_info); |
885 | sym_index = old_to_new_syms[sym_index]; |
886 | rel->r_info = ELFW(R_INFO)(sym_index, type); |
887 | } |
888 | } |
889 | } |
890 | |
891 | tcc_free(old_to_new_syms); |
892 | } |
893 | |
894 | /* relocate symbol table, resolve undefined symbols if do_resolve is |
895 | true and output error if undefined symbol. */ |
896 | ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) |
897 | { |
898 | ElfW(Sym) *sym; |
899 | int sym_bind, sh_num; |
900 | const char *name; |
901 | |
902 | for_each_elem(symtab, 1, sym, ElfW(Sym)) { |
903 | sh_num = sym->st_shndx; |
904 | if (sh_num == SHN_UNDEF) { |
905 | name = (char *) s1->symtab->link->data + sym->st_name; |
906 | /* Use ld.so to resolve symbol for us (for tcc -run) */ |
907 | if (do_resolve) { |
908 | #if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE |
909 | #ifdef TCC_TARGET_MACHO |
910 | /* The symbols in the symtables have a prepended '_' |
911 | but dlsym() needs the undecorated name. */ |
912 | void *addr = dlsym(RTLD_DEFAULT, name + 1); |
913 | #else |
914 | void *addr = dlsym(RTLD_DEFAULT, name); |
915 | #endif |
916 | if (addr) { |
917 | sym->st_value = (addr_t) addr; |
918 | #ifdef DEBUG_RELOC |
919 | printf ("relocate_sym: %s -> 0x%lx\n" , name, sym->st_value); |
920 | #endif |
921 | goto found; |
922 | } |
923 | #endif |
924 | /* if dynamic symbol exist, it will be used in relocate_section */ |
925 | } else if (s1->dynsym && find_elf_sym(s1->dynsym, name)) |
926 | goto found; |
927 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
928 | it */ |
929 | if (!strcmp(name, "_fp_hw" )) |
930 | goto found; |
931 | /* only weak symbols are accepted to be undefined. Their |
932 | value is zero */ |
933 | sym_bind = ELFW(ST_BIND)(sym->st_info); |
934 | if (sym_bind == STB_WEAK) |
935 | sym->st_value = 0; |
936 | else |
937 | tcc_error_noabort("undefined symbol '%s'" , name); |
938 | } else if (sh_num < SHN_LORESERVE) { |
939 | /* add section base */ |
940 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
941 | } |
942 | found: ; |
943 | } |
944 | } |
945 | |
946 | /* relocate a given section (CPU dependent) by applying the relocations |
947 | in the associated relocation section */ |
948 | ST_FUNC void relocate_section(TCCState *s1, Section *s) |
949 | { |
950 | Section *sr = s->reloc; |
951 | ElfW_Rel *rel; |
952 | ElfW(Sym) *sym; |
953 | int type, sym_index; |
954 | unsigned char *ptr; |
955 | addr_t tgt, addr; |
956 | |
957 | qrel = (ElfW_Rel *)sr->data; |
958 | |
959 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
960 | ptr = s->data + rel->r_offset; |
961 | sym_index = ELFW(R_SYM)(rel->r_info); |
962 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
963 | type = ELFW(R_TYPE)(rel->r_info); |
964 | tgt = sym->st_value; |
965 | #if SHT_RELX == SHT_RELA |
966 | tgt += rel->r_addend; |
967 | #endif |
968 | addr = s->sh_addr + rel->r_offset; |
969 | relocate(s1, rel, type, ptr, addr, tgt); |
970 | } |
971 | /* if the relocation is allocated, we change its symbol table */ |
972 | if (sr->sh_flags & SHF_ALLOC) { |
973 | sr->link = s1->dynsym; |
974 | if (s1->output_type == TCC_OUTPUT_DLL) { |
975 | size_t r = (uint8_t*)qrel - sr->data; |
976 | if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE |
977 | && 0 == strcmp(s->name, ".stab" )) |
978 | r = 0; /* cannot apply 64bit relocation to 32bit value */ |
979 | sr->data_offset = sr->sh_size = r; |
980 | } |
981 | } |
982 | } |
983 | |
984 | #ifndef ELF_OBJ_ONLY |
985 | /* relocate relocation table in 'sr' */ |
986 | static void relocate_rel(TCCState *s1, Section *sr) |
987 | { |
988 | Section *s; |
989 | ElfW_Rel *rel; |
990 | |
991 | s = s1->sections[sr->sh_info]; |
992 | for_each_elem(sr, 0, rel, ElfW_Rel) |
993 | rel->r_offset += s->sh_addr; |
994 | } |
995 | |
996 | /* count the number of dynamic relocations so that we can reserve |
997 | their space */ |
998 | static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
999 | { |
1000 | int count = 0; |
1001 | #if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || \ |
1002 | defined(TCC_TARGET_ARM) || defined(TCC_TARGET_ARM64) || \ |
1003 | defined(TCC_TARGET_RISCV64) |
1004 | ElfW_Rel *rel; |
1005 | for_each_elem(sr, 0, rel, ElfW_Rel) { |
1006 | int sym_index = ELFW(R_SYM)(rel->r_info); |
1007 | int type = ELFW(R_TYPE)(rel->r_info); |
1008 | switch(type) { |
1009 | #if defined(TCC_TARGET_I386) |
1010 | case R_386_32: |
1011 | if (!get_sym_attr(s1, sym_index, 0)->dyn_index |
1012 | && ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) { |
1013 | /* don't fixup unresolved (weak) symbols */ |
1014 | rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE); |
1015 | break; |
1016 | } |
1017 | #elif defined(TCC_TARGET_X86_64) |
1018 | case R_X86_64_32: |
1019 | case R_X86_64_32S: |
1020 | case R_X86_64_64: |
1021 | #elif defined(TCC_TARGET_ARM) |
1022 | case R_ARM_ABS32: |
1023 | #elif defined(TCC_TARGET_ARM64) |
1024 | case R_AARCH64_ABS32: |
1025 | case R_AARCH64_ABS64: |
1026 | #elif defined(TCC_TARGET_RISCV64) |
1027 | case R_RISCV_32: |
1028 | case R_RISCV_64: |
1029 | #endif |
1030 | count++; |
1031 | break; |
1032 | #if defined(TCC_TARGET_I386) |
1033 | case R_386_PC32: |
1034 | #elif defined(TCC_TARGET_X86_64) |
1035 | case R_X86_64_PC32: |
1036 | #elif defined(TCC_TARGET_ARM64) |
1037 | case R_AARCH64_PREL32: |
1038 | #endif |
1039 | if (get_sym_attr(s1, sym_index, 0)->dyn_index) |
1040 | count++; |
1041 | break; |
1042 | default: |
1043 | break; |
1044 | } |
1045 | } |
1046 | if (count) { |
1047 | /* allocate the section */ |
1048 | sr->sh_flags |= SHF_ALLOC; |
1049 | sr->sh_size = count * sizeof(ElfW_Rel); |
1050 | } |
1051 | #endif |
1052 | return count; |
1053 | } |
1054 | #endif |
1055 | |
1056 | #if !defined(ELF_OBJ_ONLY) || (defined(TCC_TARGET_MACHO) && defined TCC_IS_NATIVE) |
1057 | static void build_got(TCCState *s1) |
1058 | { |
1059 | /* if no got, then create it */ |
1060 | s1->got = new_section(s1, ".got" , SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
1061 | s1->got->sh_entsize = 4; |
1062 | set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
1063 | 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_" ); |
1064 | /* keep space for _DYNAMIC pointer and two dummy got entries */ |
1065 | section_ptr_add(s1->got, 3 * PTR_SIZE); |
1066 | } |
1067 | |
1068 | /* Create a GOT and (for function call) a PLT entry corresponding to a symbol |
1069 | in s1->symtab. When creating the dynamic symbol table entry for the GOT |
1070 | relocation, use 'size' and 'info' for the corresponding symbol metadata. |
1071 | Returns the offset of the GOT or (if any) PLT entry. */ |
1072 | static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, |
1073 | int sym_index) |
1074 | { |
1075 | int need_plt_entry; |
1076 | const char *name; |
1077 | ElfW(Sym) *sym; |
1078 | struct sym_attr *attr; |
1079 | unsigned got_offset; |
1080 | char plt_name[100]; |
1081 | int len; |
1082 | |
1083 | need_plt_entry = (dyn_reloc_type == R_JMP_SLOT); |
1084 | attr = get_sym_attr(s1, sym_index, 1); |
1085 | |
1086 | /* In case a function is both called and its address taken 2 GOT entries |
1087 | are created, one for taking the address (GOT) and the other for the PLT |
1088 | entry (PLTGOT). */ |
1089 | if (need_plt_entry ? attr->plt_offset : attr->got_offset) |
1090 | return attr; |
1091 | |
1092 | /* create the GOT entry */ |
1093 | got_offset = s1->got->data_offset; |
1094 | section_ptr_add(s1->got, PTR_SIZE); |
1095 | |
1096 | /* Create the GOT relocation that will insert the address of the object or |
1097 | function of interest in the GOT entry. This is a static relocation for |
1098 | memory output (dlsym will give us the address of symbols) and dynamic |
1099 | relocation otherwise (executable and DLLs). The relocation should be |
1100 | done lazily for GOT entry with *_JUMP_SLOT relocation type (the one |
1101 | associated to a PLT entry) but is currently done at load time for an |
1102 | unknown reason. */ |
1103 | |
1104 | sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
1105 | name = (char *) symtab_section->link->data + sym->st_name; |
1106 | |
1107 | if (s1->dynsym) { |
1108 | if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) { |
1109 | /* Hack alarm. We don't want to emit dynamic symbols |
1110 | and symbol based relocs for STB_LOCAL symbols, but rather |
1111 | want to resolve them directly. At this point the symbol |
1112 | values aren't final yet, so we must defer this. We will later |
1113 | have to create a RELATIVE reloc anyway, so we misuse the |
1114 | relocation slot to smuggle the symbol reference until |
1115 | fill_local_got_entries. Not that the sym_index is |
1116 | relative to symtab_section, not s1->dynsym! Nevertheless |
1117 | we use s1->dyn_sym so that if this is the first call |
1118 | that got->reloc is correctly created. Also note that |
1119 | RELATIVE relocs are not normally created for the .got, |
1120 | so the types serves as a marker for later (and is retained |
1121 | also for the final output, which is okay because then the |
1122 | got is just normal data). */ |
1123 | put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE, |
1124 | sym_index); |
1125 | } else { |
1126 | if (0 == attr->dyn_index) |
1127 | attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value, |
1128 | sym->st_size, sym->st_info, 0, |
1129 | sym->st_shndx, name); |
1130 | put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type, |
1131 | attr->dyn_index); |
1132 | } |
1133 | } else { |
1134 | put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type, |
1135 | sym_index); |
1136 | } |
1137 | |
1138 | if (need_plt_entry) { |
1139 | if (!s1->plt) { |
1140 | s1->plt = new_section(s1, ".plt" , SHT_PROGBITS, |
1141 | SHF_ALLOC | SHF_EXECINSTR); |
1142 | s1->plt->sh_entsize = 4; |
1143 | } |
1144 | |
1145 | attr->plt_offset = create_plt_entry(s1, got_offset, attr); |
1146 | |
1147 | /* create a symbol 'sym@plt' for the PLT jump vector */ |
1148 | len = strlen(name); |
1149 | if (len > sizeof plt_name - 5) |
1150 | len = sizeof plt_name - 5; |
1151 | memcpy(plt_name, name, len); |
1152 | strcpy(plt_name + len, "@plt" ); |
1153 | attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size, |
1154 | ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name); |
1155 | |
1156 | } else { |
1157 | attr->got_offset = got_offset; |
1158 | } |
1159 | |
1160 | return attr; |
1161 | } |
1162 | |
1163 | /* build GOT and PLT entries */ |
1164 | ST_FUNC void build_got_entries(TCCState *s1) |
1165 | { |
1166 | Section *s; |
1167 | ElfW_Rel *rel; |
1168 | ElfW(Sym) *sym; |
1169 | int i, type, gotplt_entry, reloc_type, sym_index; |
1170 | struct sym_attr *attr; |
1171 | |
1172 | for(i = 1; i < s1->nb_sections; i++) { |
1173 | s = s1->sections[i]; |
1174 | if (s->sh_type != SHT_RELX) |
1175 | continue; |
1176 | /* no need to handle got relocations */ |
1177 | if (s->link != symtab_section) |
1178 | continue; |
1179 | for_each_elem(s, 0, rel, ElfW_Rel) { |
1180 | type = ELFW(R_TYPE)(rel->r_info); |
1181 | gotplt_entry = gotplt_entry_type(type); |
1182 | if (gotplt_entry == -1) |
1183 | tcc_error ("Unknown relocation type for got: %d" , type); |
1184 | sym_index = ELFW(R_SYM)(rel->r_info); |
1185 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
1186 | |
1187 | if (gotplt_entry == NO_GOTPLT_ENTRY) { |
1188 | continue; |
1189 | } |
1190 | |
1191 | /* Automatically create PLT/GOT [entry] if it is an undefined |
1192 | reference (resolved at runtime), or the symbol is absolute, |
1193 | probably created by tcc_add_symbol, and thus on 64-bit |
1194 | targets might be too far from application code. */ |
1195 | if (gotplt_entry == AUTO_GOTPLT_ENTRY) { |
1196 | if (sym->st_shndx == SHN_UNDEF) { |
1197 | ElfW(Sym) *esym; |
1198 | int dynindex; |
1199 | if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT) |
1200 | continue; |
1201 | /* Relocations for UNDEF symbols would normally need |
1202 | to be transferred into the executable or shared object. |
1203 | If that were done AUTO_GOTPLT_ENTRY wouldn't exist. |
1204 | But TCC doesn't do that (at least for exes), so we |
1205 | need to resolve all such relocs locally. And that |
1206 | means PLT slots for functions in DLLs and COPY relocs for |
1207 | data symbols. COPY relocs were generated in |
1208 | bind_exe_dynsyms (and the symbol adjusted to be defined), |
1209 | and for functions we were generated a dynamic symbol |
1210 | of function type. */ |
1211 | if (s1->dynsym) { |
1212 | /* dynsym isn't set for -run :-/ */ |
1213 | dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index; |
1214 | esym = (ElfW(Sym) *)s1->dynsym->data + dynindex; |
1215 | if (dynindex |
1216 | && (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC |
1217 | || (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE |
1218 | && ELFW(ST_TYPE)(sym->st_info) == STT_FUNC))) |
1219 | goto jmp_slot; |
1220 | } |
1221 | } else if (!(sym->st_shndx == SHN_ABS |
1222 | #ifndef TCC_TARGET_ARM |
1223 | && PTR_SIZE == 8 |
1224 | #endif |
1225 | )) |
1226 | continue; |
1227 | } |
1228 | |
1229 | #ifdef TCC_TARGET_X86_64 |
1230 | if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) && |
1231 | sym->st_shndx != SHN_UNDEF && |
1232 | (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || |
1233 | ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || |
1234 | s1->output_type == TCC_OUTPUT_EXE)) { |
1235 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); |
1236 | continue; |
1237 | } |
1238 | #endif |
1239 | reloc_type = code_reloc(type); |
1240 | if (reloc_type == -1) |
1241 | tcc_error ("Unknown relocation type: %d" , type); |
1242 | else if (reloc_type != 0) { |
1243 | jmp_slot: |
1244 | reloc_type = R_JMP_SLOT; |
1245 | } else |
1246 | reloc_type = R_GLOB_DAT; |
1247 | |
1248 | if (!s1->got) |
1249 | build_got(s1); |
1250 | |
1251 | if (gotplt_entry == BUILD_GOT_ONLY) |
1252 | continue; |
1253 | |
1254 | attr = put_got_entry(s1, reloc_type, sym_index); |
1255 | |
1256 | if (reloc_type == R_JMP_SLOT) |
1257 | rel->r_info = ELFW(R_INFO)(attr->plt_sym, type); |
1258 | } |
1259 | } |
1260 | } |
1261 | #endif |
1262 | |
1263 | ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) |
1264 | { |
1265 | int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF; |
1266 | if (sec && offs == -1) |
1267 | offs = sec->data_offset; |
1268 | return set_elf_sym(symtab_section, offs, 0, |
1269 | ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name); |
1270 | } |
1271 | |
1272 | static void add_init_array_defines(TCCState *s1, const char *section_name) |
1273 | { |
1274 | Section *s; |
1275 | addr_t end_offset; |
1276 | char buf[1024]; |
1277 | s = find_section(s1, section_name); |
1278 | if (!s) { |
1279 | end_offset = 0; |
1280 | s = data_section; |
1281 | } else { |
1282 | end_offset = s->data_offset; |
1283 | } |
1284 | snprintf(buf, sizeof(buf), "__%s_start" , section_name + 1); |
1285 | set_global_sym(s1, buf, s, 0); |
1286 | snprintf(buf, sizeof(buf), "__%s_end" , section_name + 1); |
1287 | set_global_sym(s1, buf, s, end_offset); |
1288 | } |
1289 | |
1290 | #ifndef TCC_TARGET_PE |
1291 | static void tcc_add_support(TCCState *s1, const char *filename) |
1292 | { |
1293 | char buf[1024]; |
1294 | snprintf(buf, sizeof(buf), "%s/%s" , s1->tcc_lib_path, filename); |
1295 | tcc_add_file(s1, buf); |
1296 | } |
1297 | #endif |
1298 | |
1299 | ST_FUNC void add_array (TCCState *s1, const char *sec, int c) |
1300 | { |
1301 | Section *s; |
1302 | s = find_section(s1, sec); |
1303 | s->sh_flags |= SHF_WRITE; |
1304 | #ifndef TCC_TARGET_PE |
1305 | s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY; |
1306 | #endif |
1307 | put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); |
1308 | section_ptr_add(s, PTR_SIZE); |
1309 | } |
1310 | |
1311 | #ifdef CONFIG_TCC_BCHECK |
1312 | ST_FUNC void tcc_add_bcheck(TCCState *s1) |
1313 | { |
1314 | if (0 == s1->do_bounds_check) |
1315 | return; |
1316 | section_ptr_add(bounds_section, sizeof(addr_t)); |
1317 | } |
1318 | #endif |
1319 | |
1320 | #ifdef CONFIG_TCC_BACKTRACE |
1321 | static void put_ptr(TCCState *s1, Section *s, int offs) |
1322 | { |
1323 | int c; |
1324 | c = set_global_sym(s1, NULL, s, offs); |
1325 | s = data_section; |
1326 | put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c); |
1327 | section_ptr_add(s, PTR_SIZE); |
1328 | } |
1329 | |
1330 | /* set symbol to STB_LOCAL and resolve. The point is to not export it as |
1331 | a dynamic symbol to allow so's to have one each with a different value. */ |
1332 | static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset) |
1333 | { |
1334 | int c = find_elf_sym(s1->symtab, name); |
1335 | if (c) { |
1336 | ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c; |
1337 | esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE); |
1338 | esym->st_value = offset; |
1339 | esym->st_shndx = s->sh_num; |
1340 | } |
1341 | } |
1342 | |
1343 | ST_FUNC void tcc_add_btstub(TCCState *s1) |
1344 | { |
1345 | Section *s; |
1346 | int n, o; |
1347 | CString cstr; |
1348 | |
1349 | s = data_section; |
1350 | o = s->data_offset; |
1351 | /* create (part of) a struct rt_context (see tccrun.c) */ |
1352 | put_ptr(s1, stab_section, 0); |
1353 | put_ptr(s1, stab_section, -1); |
1354 | put_ptr(s1, stab_section->link, 0); |
1355 | section_ptr_add(s, 3 * PTR_SIZE); |
1356 | /* prog_base */ |
1357 | #ifndef TCC_TARGET_MACHO |
1358 | /* XXX this relocation is wrong, it uses sym-index 0 (local,undef) */ |
1359 | put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0); |
1360 | #endif |
1361 | section_ptr_add(s, PTR_SIZE); |
1362 | n = 2 * PTR_SIZE; |
1363 | #ifdef CONFIG_TCC_BCHECK |
1364 | if (s1->do_bounds_check) { |
1365 | put_ptr(s1, bounds_section, 0); |
1366 | n -= PTR_SIZE; |
1367 | } |
1368 | #endif |
1369 | section_ptr_add(s, n); |
1370 | |
1371 | cstr_new(&cstr); |
1372 | cstr_printf(&cstr, |
1373 | " extern void __bt_init(),*__rt_info[],__bt_init_dll();" |
1374 | "__attribute__((constructor)) static void __bt_init_rt(){" ); |
1375 | #ifdef TCC_TARGET_PE |
1376 | if (s1->output_type == TCC_OUTPUT_DLL) |
1377 | #ifdef CONFIG_TCC_BCHECK |
1378 | cstr_printf(&cstr, "__bt_init_dll(%d);" , s1->do_bounds_check); |
1379 | #else |
1380 | cstr_printf(&cstr, "__bt_init_dll(0);" ); |
1381 | #endif |
1382 | #endif |
1383 | cstr_printf(&cstr, "__bt_init(__rt_info,%d, 0);}" , |
1384 | s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1); |
1385 | tcc_compile_string(s1, cstr.data); |
1386 | cstr_free(&cstr); |
1387 | set_local_sym(s1, &"___rt_info" [!s1->leading_underscore], s, o); |
1388 | } |
1389 | #endif |
1390 | |
1391 | #ifndef TCC_TARGET_PE |
1392 | /* add tcc runtime libraries */ |
1393 | ST_FUNC void tcc_add_runtime(TCCState *s1) |
1394 | { |
1395 | s1->filetype = 0; |
1396 | #ifdef CONFIG_TCC_BCHECK |
1397 | tcc_add_bcheck(s1); |
1398 | #endif |
1399 | tcc_add_pragma_libs(s1); |
1400 | /* add libc */ |
1401 | if (!s1->nostdlib) { |
1402 | if (s1->option_pthread) |
1403 | tcc_add_library_err(s1, "pthread" ); |
1404 | tcc_add_library_err(s1, "c" ); |
1405 | #ifdef TCC_LIBGCC |
1406 | if (!s1->static_link) { |
1407 | if (TCC_LIBGCC[0] == '/') |
1408 | tcc_add_file(s1, TCC_LIBGCC); |
1409 | else |
1410 | tcc_add_dll(s1, TCC_LIBGCC, 0); |
1411 | } |
1412 | #endif |
1413 | #ifdef CONFIG_TCC_BCHECK |
1414 | if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) { |
1415 | tcc_add_library_err(s1, "pthread" ); |
1416 | tcc_add_library_err(s1, "dl" ); |
1417 | tcc_add_support(s1, "bcheck.o" ); |
1418 | } |
1419 | #endif |
1420 | #ifdef CONFIG_TCC_BACKTRACE |
1421 | if (s1->do_backtrace) { |
1422 | if (s1->output_type == TCC_OUTPUT_EXE) |
1423 | tcc_add_support(s1, "bt-exe.o" ); |
1424 | if (s1->output_type != TCC_OUTPUT_DLL) |
1425 | tcc_add_support(s1, "bt-log.o" ); |
1426 | if (s1->output_type != TCC_OUTPUT_MEMORY) |
1427 | tcc_add_btstub(s1); |
1428 | } |
1429 | #endif |
1430 | if (strlen(TCC_LIBTCC1) > 0) |
1431 | tcc_add_support(s1, TCC_LIBTCC1); |
1432 | #ifndef TCC_TARGET_MACHO |
1433 | /* add crt end if not memory output */ |
1434 | if (s1->output_type != TCC_OUTPUT_MEMORY) |
1435 | tcc_add_crt(s1, "crtn.o" ); |
1436 | #endif |
1437 | } |
1438 | } |
1439 | #endif |
1440 | |
1441 | /* add various standard linker symbols (must be done after the |
1442 | sections are filled (for example after allocating common |
1443 | symbols)) */ |
1444 | static void tcc_add_linker_symbols(TCCState *s1) |
1445 | { |
1446 | char buf[1024]; |
1447 | int i; |
1448 | Section *s; |
1449 | |
1450 | set_global_sym(s1, "_etext" , text_section, -1); |
1451 | set_global_sym(s1, "_edata" , data_section, -1); |
1452 | set_global_sym(s1, "_end" , bss_section, -1); |
1453 | #ifdef TCC_TARGET_RISCV64 |
1454 | /* XXX should be .sdata+0x800, not .data+0x800 */ |
1455 | set_global_sym(s1, "__global_pointer$" , data_section, 0x800); |
1456 | #endif |
1457 | /* horrible new standard ldscript defines */ |
1458 | add_init_array_defines(s1, ".preinit_array" ); |
1459 | add_init_array_defines(s1, ".init_array" ); |
1460 | add_init_array_defines(s1, ".fini_array" ); |
1461 | /* add start and stop symbols for sections whose name can be |
1462 | expressed in C */ |
1463 | for(i = 1; i < s1->nb_sections; i++) { |
1464 | s = s1->sections[i]; |
1465 | if ((s->sh_flags & SHF_ALLOC) |
1466 | && (s->sh_type == SHT_PROGBITS |
1467 | || s->sh_type == SHT_STRTAB)) { |
1468 | const char *p; |
1469 | /* check if section name can be expressed in C */ |
1470 | p = s->name; |
1471 | for(;;) { |
1472 | int c = *p; |
1473 | if (!c) |
1474 | break; |
1475 | if (!isid(c) && !isnum(c)) |
1476 | goto next_sec; |
1477 | p++; |
1478 | } |
1479 | snprintf(buf, sizeof(buf), "__start_%s" , s->name); |
1480 | set_global_sym(s1, buf, s, 0); |
1481 | snprintf(buf, sizeof(buf), "__stop_%s" , s->name); |
1482 | set_global_sym(s1, buf, s, -1); |
1483 | } |
1484 | next_sec: ; |
1485 | } |
1486 | } |
1487 | |
1488 | ST_FUNC void resolve_common_syms(TCCState *s1) |
1489 | { |
1490 | ElfW(Sym) *sym; |
1491 | |
1492 | /* Allocate common symbols in BSS. */ |
1493 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
1494 | if (sym->st_shndx == SHN_COMMON) { |
1495 | /* symbol alignment is in st_value for SHN_COMMONs */ |
1496 | sym->st_value = section_add(bss_section, sym->st_size, |
1497 | sym->st_value); |
1498 | sym->st_shndx = bss_section->sh_num; |
1499 | } |
1500 | } |
1501 | |
1502 | /* Now assign linker provided symbols their value. */ |
1503 | tcc_add_linker_symbols(s1); |
1504 | } |
1505 | |
1506 | static void tcc_output_binary(TCCState *s1, FILE *f, |
1507 | const int *sec_order) |
1508 | { |
1509 | Section *s; |
1510 | int i, offset, size; |
1511 | |
1512 | offset = 0; |
1513 | for(i=1;i<s1->nb_sections;i++) { |
1514 | s = s1->sections[sec_order[i]]; |
1515 | if (s->sh_type != SHT_NOBITS && |
1516 | (s->sh_flags & SHF_ALLOC)) { |
1517 | while (offset < s->sh_offset) { |
1518 | fputc(0, f); |
1519 | offset++; |
1520 | } |
1521 | size = s->sh_size; |
1522 | fwrite(s->data, 1, size, f); |
1523 | offset += size; |
1524 | } |
1525 | } |
1526 | } |
1527 | |
1528 | #ifndef ELF_OBJ_ONLY |
1529 | ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) |
1530 | { |
1531 | int sym_index = ELFW(R_SYM) (rel->r_info); |
1532 | ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
1533 | struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); |
1534 | unsigned offset = attr->got_offset; |
1535 | |
1536 | if (0 == offset) |
1537 | return; |
1538 | section_reserve(s1->got, offset + PTR_SIZE); |
1539 | #if PTR_SIZE == 8 |
1540 | write64le(s1->got->data + offset, sym->st_value); |
1541 | #else |
1542 | write32le(s1->got->data + offset, sym->st_value); |
1543 | #endif |
1544 | } |
1545 | |
1546 | /* Perform relocation to GOT or PLT entries */ |
1547 | ST_FUNC void fill_got(TCCState *s1) |
1548 | { |
1549 | Section *s; |
1550 | ElfW_Rel *rel; |
1551 | int i; |
1552 | |
1553 | for(i = 1; i < s1->nb_sections; i++) { |
1554 | s = s1->sections[i]; |
1555 | if (s->sh_type != SHT_RELX) |
1556 | continue; |
1557 | /* no need to handle got relocations */ |
1558 | if (s->link != symtab_section) |
1559 | continue; |
1560 | for_each_elem(s, 0, rel, ElfW_Rel) { |
1561 | switch (ELFW(R_TYPE) (rel->r_info)) { |
1562 | case R_X86_64_GOT32: |
1563 | case R_X86_64_GOTPCREL: |
1564 | case R_X86_64_GOTPCRELX: |
1565 | case R_X86_64_REX_GOTPCRELX: |
1566 | case R_X86_64_PLT32: |
1567 | fill_got_entry(s1, rel); |
1568 | break; |
1569 | } |
1570 | } |
1571 | } |
1572 | } |
1573 | |
1574 | /* See put_got_entry for a description. This is the second stage |
1575 | where GOT references to local defined symbols are rewritten. */ |
1576 | static void fill_local_got_entries(TCCState *s1) |
1577 | { |
1578 | ElfW_Rel *rel; |
1579 | if (!s1->got->reloc) |
1580 | return; |
1581 | for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) { |
1582 | if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) { |
1583 | int sym_index = ELFW(R_SYM) (rel->r_info); |
1584 | ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
1585 | struct sym_attr *attr = get_sym_attr(s1, sym_index, 0); |
1586 | unsigned offset = attr->got_offset; |
1587 | if (offset != rel->r_offset - s1->got->sh_addr) |
1588 | tcc_error_noabort("huh" ); |
1589 | rel->r_info = ELFW(R_INFO)(0, R_RELATIVE); |
1590 | #if SHT_RELX == SHT_RELA |
1591 | rel->r_addend = sym->st_value; |
1592 | #else |
1593 | /* All our REL architectures also happen to be 32bit LE. */ |
1594 | write32le(s1->got->data + offset, sym->st_value); |
1595 | #endif |
1596 | } |
1597 | } |
1598 | } |
1599 | |
1600 | /* Bind symbols of executable: resolve undefined symbols from exported symbols |
1601 | in shared libraries and export non local defined symbols to shared libraries |
1602 | if -rdynamic switch was given on command line */ |
1603 | static void bind_exe_dynsyms(TCCState *s1) |
1604 | { |
1605 | const char *name; |
1606 | int sym_index, index; |
1607 | ElfW(Sym) *sym, *esym; |
1608 | int type; |
1609 | |
1610 | /* Resolve undefined symbols from dynamic symbols. When there is a match: |
1611 | - if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT |
1612 | - if STT_OBJECT symbol -> add it in .bss section with suitable reloc */ |
1613 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
1614 | if (sym->st_shndx == SHN_UNDEF) { |
1615 | name = (char *) symtab_section->link->data + sym->st_name; |
1616 | sym_index = find_elf_sym(s1->dynsymtab_section, name); |
1617 | if (sym_index) { |
1618 | esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; |
1619 | type = ELFW(ST_TYPE)(esym->st_info); |
1620 | if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { |
1621 | /* Indirect functions shall have STT_FUNC type in executable |
1622 | * dynsym section. Indeed, a dlsym call following a lazy |
1623 | * resolution would pick the symbol value from the |
1624 | * executable dynsym entry which would contain the address |
1625 | * of the function wanted by the caller of dlsym instead of |
1626 | * the address of the function that would return that |
1627 | * address */ |
1628 | int dynindex |
1629 | = put_elf_sym(s1->dynsym, 0, esym->st_size, |
1630 | ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0, |
1631 | name); |
1632 | int index = sym - (ElfW(Sym) *) symtab_section->data; |
1633 | get_sym_attr(s1, index, 1)->dyn_index = dynindex; |
1634 | } else if (type == STT_OBJECT) { |
1635 | unsigned long offset; |
1636 | ElfW(Sym) *dynsym; |
1637 | offset = bss_section->data_offset; |
1638 | /* XXX: which alignment ? */ |
1639 | offset = (offset + 16 - 1) & -16; |
1640 | set_elf_sym (s1->symtab, offset, esym->st_size, |
1641 | esym->st_info, 0, bss_section->sh_num, name); |
1642 | index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
1643 | esym->st_info, 0, bss_section->sh_num, |
1644 | name); |
1645 | |
1646 | /* Ensure R_COPY works for weak symbol aliases */ |
1647 | if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { |
1648 | for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) { |
1649 | if ((dynsym->st_value == esym->st_value) |
1650 | && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { |
1651 | char *dynname = (char *) s1->dynsymtab_section->link->data |
1652 | + dynsym->st_name; |
1653 | put_elf_sym(s1->dynsym, offset, dynsym->st_size, |
1654 | dynsym->st_info, 0, |
1655 | bss_section->sh_num, dynname); |
1656 | break; |
1657 | } |
1658 | } |
1659 | } |
1660 | |
1661 | put_elf_reloc(s1->dynsym, bss_section, |
1662 | offset, R_COPY, index); |
1663 | offset += esym->st_size; |
1664 | bss_section->data_offset = offset; |
1665 | } |
1666 | } else { |
1667 | /* STB_WEAK undefined symbols are accepted */ |
1668 | /* XXX: _fp_hw seems to be part of the ABI, so we ignore it */ |
1669 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || |
1670 | !strcmp(name, "_fp_hw" )) { |
1671 | } else { |
1672 | tcc_error_noabort("undefined symbol '%s'" , name); |
1673 | } |
1674 | } |
1675 | } else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
1676 | /* if -rdynamic option, then export all non local symbols */ |
1677 | name = (char *) symtab_section->link->data + sym->st_name; |
1678 | set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info, |
1679 | 0, sym->st_shndx, name); |
1680 | } |
1681 | } |
1682 | } |
1683 | |
1684 | /* Bind symbols of libraries: export all non local symbols of executable that |
1685 | are referenced by shared libraries. The reason is that the dynamic loader |
1686 | search symbol first in executable and then in libraries. Therefore a |
1687 | reference to a symbol already defined by a library can still be resolved by |
1688 | a symbol in the executable. */ |
1689 | static void bind_libs_dynsyms(TCCState *s1) |
1690 | { |
1691 | const char *name; |
1692 | int sym_index; |
1693 | ElfW(Sym) *sym, *esym; |
1694 | |
1695 | for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) { |
1696 | name = (char *) s1->dynsymtab_section->link->data + esym->st_name; |
1697 | sym_index = find_elf_sym(symtab_section, name); |
1698 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
1699 | if (sym_index && sym->st_shndx != SHN_UNDEF |
1700 | && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
1701 | set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1702 | sym->st_info, 0, sym->st_shndx, name); |
1703 | } else if (esym->st_shndx == SHN_UNDEF) { |
1704 | /* weak symbols can stay undefined */ |
1705 | if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK) |
1706 | tcc_warning("undefined dynamic symbol '%s'" , name); |
1707 | } |
1708 | } |
1709 | } |
1710 | |
1711 | /* Export all non local symbols. This is used by shared libraries so that the |
1712 | non local symbols they define can resolve a reference in another shared |
1713 | library or in the executable. Correspondingly, it allows undefined local |
1714 | symbols to be resolved by other shared libraries or by the executable. */ |
1715 | static void export_global_syms(TCCState *s1) |
1716 | { |
1717 | int dynindex, index; |
1718 | const char *name; |
1719 | ElfW(Sym) *sym; |
1720 | |
1721 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
1722 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
1723 | name = (char *) symtab_section->link->data + sym->st_name; |
1724 | dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
1725 | sym->st_info, 0, sym->st_shndx, name); |
1726 | index = sym - (ElfW(Sym) *) symtab_section->data; |
1727 | get_sym_attr(s1, index, 1)->dyn_index = dynindex; |
1728 | } |
1729 | } |
1730 | } |
1731 | #endif |
1732 | |
1733 | /* Allocate strings for section names and decide if an unallocated section |
1734 | should be output. |
1735 | NOTE: the strsec section comes last, so its size is also correct ! */ |
1736 | static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec) |
1737 | { |
1738 | int i; |
1739 | Section *s; |
1740 | int textrel = 0; |
1741 | |
1742 | /* Allocate strings for section names */ |
1743 | for(i = 1; i < s1->nb_sections; i++) { |
1744 | s = s1->sections[i]; |
1745 | /* when generating a DLL, we include relocations but we may |
1746 | patch them */ |
1747 | #ifndef ELF_OBJ_ONLY |
1748 | if (file_type == TCC_OUTPUT_DLL && |
1749 | s->sh_type == SHT_RELX && |
1750 | !(s->sh_flags & SHF_ALLOC) && |
1751 | (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) && |
1752 | prepare_dynamic_rel(s1, s)) { |
1753 | if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) |
1754 | textrel = 1; |
1755 | } else |
1756 | #endif |
1757 | if ((s1->do_debug && s->sh_type != SHT_RELX) || |
1758 | file_type == TCC_OUTPUT_OBJ || |
1759 | (s->sh_flags & SHF_ALLOC) || |
1760 | i == (s1->nb_sections - 1) |
1761 | #ifdef TCC_TARGET_ARM |
1762 | || s->sh_type == SHT_ARM_ATTRIBUTES |
1763 | #endif |
1764 | ) { |
1765 | /* we output all sections if debug or object file */ |
1766 | s->sh_size = s->data_offset; |
1767 | } |
1768 | #ifdef TCC_TARGET_ARM |
1769 | /* XXX: Suppress stack unwinding section. */ |
1770 | if (s->sh_type == SHT_ARM_EXIDX) { |
1771 | s->sh_flags = 0; |
1772 | s->sh_size = 0; |
1773 | } |
1774 | #endif |
1775 | if (s->sh_size || (s->sh_flags & SHF_ALLOC)) |
1776 | s->sh_name = put_elf_str(strsec, s->name); |
1777 | } |
1778 | strsec->sh_size = strsec->data_offset; |
1779 | return textrel; |
1780 | } |
1781 | |
1782 | /* Info to be copied in dynamic section */ |
1783 | struct dyn_inf { |
1784 | Section *dynamic; |
1785 | Section *dynstr; |
1786 | unsigned long data_offset; |
1787 | addr_t rel_addr; |
1788 | addr_t rel_size; |
1789 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
1790 | addr_t bss_addr; |
1791 | addr_t bss_size; |
1792 | #endif |
1793 | }; |
1794 | |
1795 | /* Assign sections to segments and decide how are sections laid out when loaded |
1796 | in memory. This function also fills corresponding program headers. */ |
1797 | static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, |
1798 | Section *interp, Section* strsec, |
1799 | struct dyn_inf *dyninf, int *sec_order) |
1800 | { |
1801 | int i, j, k, file_type, sh_order_index, file_offset; |
1802 | unsigned long s_align; |
1803 | long long tmp; |
1804 | addr_t addr; |
1805 | ElfW(Phdr) *ph; |
1806 | Section *s; |
1807 | |
1808 | file_type = s1->output_type; |
1809 | sh_order_index = 1; |
1810 | file_offset = 0; |
1811 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
1812 | file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
1813 | s_align = ELF_PAGE_SIZE; |
1814 | if (s1->section_align) |
1815 | s_align = s1->section_align; |
1816 | |
1817 | if (phnum > 0) { |
1818 | if (s1->has_text_addr) { |
1819 | int a_offset, p_offset; |
1820 | addr = s1->text_addr; |
1821 | /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
1822 | ELF_PAGE_SIZE */ |
1823 | a_offset = (int) (addr & (s_align - 1)); |
1824 | p_offset = file_offset & (s_align - 1); |
1825 | if (a_offset < p_offset) |
1826 | a_offset += s_align; |
1827 | file_offset += (a_offset - p_offset); |
1828 | } else { |
1829 | if (file_type == TCC_OUTPUT_DLL) |
1830 | addr = 0; |
1831 | else |
1832 | addr = ELF_START_ADDR; |
1833 | /* compute address after headers */ |
1834 | addr += (file_offset & (s_align - 1)); |
1835 | } |
1836 | |
1837 | ph = &phdr[0]; |
1838 | /* Leave one program headers for the program interpreter and one for |
1839 | the program header table itself if needed. These are done later as |
1840 | they require section layout to be done first. */ |
1841 | if (interp) |
1842 | ph += 2; |
1843 | |
1844 | /* dynamic relocation table information, for .dynamic section */ |
1845 | dyninf->rel_addr = dyninf->rel_size = 0; |
1846 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
1847 | dyninf->bss_addr = dyninf->bss_size = 0; |
1848 | #endif |
1849 | |
1850 | for(j = 0; j < (phnum == 6 ? 3 : 2); j++) { |
1851 | ph->p_type = j == 2 ? PT_TLS : PT_LOAD; |
1852 | if (j == 0) |
1853 | ph->p_flags = PF_R | PF_X; |
1854 | else |
1855 | ph->p_flags = PF_R | PF_W; |
1856 | ph->p_align = j == 2 ? 4 : s_align; |
1857 | |
1858 | /* Decide the layout of sections loaded in memory. This must |
1859 | be done before program headers are filled since they contain |
1860 | info about the layout. We do the following ordering: interp, |
1861 | symbol tables, relocations, progbits, nobits */ |
1862 | /* XXX: do faster and simpler sorting */ |
1863 | for(k = 0; k < 5; k++) { |
1864 | for(i = 1; i < s1->nb_sections; i++) { |
1865 | s = s1->sections[i]; |
1866 | /* compute if section should be included */ |
1867 | if (j == 0) { |
1868 | if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != |
1869 | SHF_ALLOC) |
1870 | continue; |
1871 | } else if (j == 1) { |
1872 | if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != |
1873 | (SHF_ALLOC | SHF_WRITE)) |
1874 | continue; |
1875 | } else { |
1876 | if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) != |
1877 | (SHF_ALLOC | SHF_WRITE | SHF_TLS)) |
1878 | continue; |
1879 | } |
1880 | if (s == interp) { |
1881 | if (k != 0) |
1882 | continue; |
1883 | } else if ((s->sh_type == SHT_DYNSYM || |
1884 | s->sh_type == SHT_STRTAB || |
1885 | s->sh_type == SHT_HASH) |
1886 | && !strstr(s->name, ".stab" )) { |
1887 | if (k != 1) |
1888 | continue; |
1889 | } else if (s->sh_type == SHT_RELX) { |
1890 | if (k != 2) |
1891 | continue; |
1892 | } else if (s->sh_type == SHT_NOBITS) { |
1893 | if (k != 4) |
1894 | continue; |
1895 | } else { |
1896 | if (k != 3) |
1897 | continue; |
1898 | } |
1899 | sec_order[sh_order_index++] = i; |
1900 | |
1901 | /* section matches: we align it and add its size */ |
1902 | tmp = addr; |
1903 | addr = (addr + s->sh_addralign - 1) & |
1904 | ~(s->sh_addralign - 1); |
1905 | file_offset += (int) ( addr - tmp ); |
1906 | s->sh_offset = file_offset; |
1907 | s->sh_addr = addr; |
1908 | |
1909 | /* update program header infos */ |
1910 | if (ph->p_offset == 0) { |
1911 | ph->p_offset = file_offset; |
1912 | ph->p_vaddr = addr; |
1913 | ph->p_paddr = ph->p_vaddr; |
1914 | } |
1915 | /* update dynamic relocation infos */ |
1916 | if (s->sh_type == SHT_RELX) { |
1917 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
1918 | if (!strcmp(strsec->data + s->sh_name, ".rel.got" )) { |
1919 | dyninf->rel_addr = addr; |
1920 | dyninf->rel_size += s->sh_size; /* XXX only first rel. */ |
1921 | } |
1922 | if (!strcmp(strsec->data + s->sh_name, ".rel.bss" )) { |
1923 | dyninf->bss_addr = addr; |
1924 | dyninf->bss_size = s->sh_size; /* XXX only first rel. */ |
1925 | } |
1926 | #else |
1927 | if (dyninf->rel_size == 0) |
1928 | dyninf->rel_addr = addr; |
1929 | dyninf->rel_size += s->sh_size; |
1930 | #endif |
1931 | } |
1932 | addr += s->sh_size; |
1933 | if (s->sh_type != SHT_NOBITS) |
1934 | file_offset += s->sh_size; |
1935 | } |
1936 | } |
1937 | if (j == 0) { |
1938 | /* Make the first PT_LOAD segment include the program |
1939 | headers itself (and the ELF header as well), it'll |
1940 | come out with same memory use but will make various |
1941 | tools like binutils strip work better. */ |
1942 | ph->p_offset &= ~(ph->p_align - 1); |
1943 | ph->p_vaddr &= ~(ph->p_align - 1); |
1944 | ph->p_paddr &= ~(ph->p_align - 1); |
1945 | } |
1946 | ph->p_filesz = file_offset - ph->p_offset; |
1947 | ph->p_memsz = addr - ph->p_vaddr; |
1948 | ph++; |
1949 | if (j == 0) { |
1950 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
1951 | /* if in the middle of a page, we duplicate the page in |
1952 | memory so that one copy is RX and the other is RW */ |
1953 | if ((addr & (s_align - 1)) != 0) |
1954 | addr += s_align; |
1955 | } else { |
1956 | addr = (addr + s_align - 1) & ~(s_align - 1); |
1957 | file_offset = (file_offset + s_align - 1) & ~(s_align - 1); |
1958 | } |
1959 | } |
1960 | } |
1961 | } |
1962 | |
1963 | /* all other sections come after */ |
1964 | for(i = 1; i < s1->nb_sections; i++) { |
1965 | s = s1->sections[i]; |
1966 | if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
1967 | continue; |
1968 | sec_order[sh_order_index++] = i; |
1969 | |
1970 | file_offset = (file_offset + s->sh_addralign - 1) & |
1971 | ~(s->sh_addralign - 1); |
1972 | s->sh_offset = file_offset; |
1973 | if (s->sh_type != SHT_NOBITS) |
1974 | file_offset += s->sh_size; |
1975 | } |
1976 | |
1977 | return file_offset; |
1978 | } |
1979 | |
1980 | #ifndef ELF_OBJ_ONLY |
1981 | /* put dynamic tag */ |
1982 | static void put_dt(Section *dynamic, int dt, addr_t val) |
1983 | { |
1984 | ElfW(Dyn) *dyn; |
1985 | dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); |
1986 | dyn->d_tag = dt; |
1987 | dyn->d_un.d_val = val; |
1988 | } |
1989 | |
1990 | static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, |
1991 | Section *dynamic) |
1992 | { |
1993 | ElfW(Phdr) *ph; |
1994 | |
1995 | /* if interpreter, then add corresponding program header */ |
1996 | if (interp) { |
1997 | ph = &phdr[0]; |
1998 | |
1999 | ph->p_type = PT_PHDR; |
2000 | ph->p_offset = sizeof(ElfW(Ehdr)); |
2001 | ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr)); |
2002 | ph->p_vaddr = interp->sh_addr - ph->p_filesz; |
2003 | ph->p_paddr = ph->p_vaddr; |
2004 | ph->p_flags = PF_R | PF_X; |
2005 | ph->p_align = 4; /* interp->sh_addralign; */ |
2006 | ph++; |
2007 | |
2008 | ph->p_type = PT_INTERP; |
2009 | ph->p_offset = interp->sh_offset; |
2010 | ph->p_vaddr = interp->sh_addr; |
2011 | ph->p_paddr = ph->p_vaddr; |
2012 | ph->p_filesz = interp->sh_size; |
2013 | ph->p_memsz = interp->sh_size; |
2014 | ph->p_flags = PF_R; |
2015 | ph->p_align = interp->sh_addralign; |
2016 | } |
2017 | |
2018 | /* if dynamic section, then add corresponding program header */ |
2019 | if (dynamic) { |
2020 | ph = &phdr[phnum - 1]; |
2021 | |
2022 | ph->p_type = PT_DYNAMIC; |
2023 | ph->p_offset = dynamic->sh_offset; |
2024 | ph->p_vaddr = dynamic->sh_addr; |
2025 | ph->p_paddr = ph->p_vaddr; |
2026 | ph->p_filesz = dynamic->sh_size; |
2027 | ph->p_memsz = dynamic->sh_size; |
2028 | ph->p_flags = PF_R | PF_W; |
2029 | ph->p_align = dynamic->sh_addralign; |
2030 | } |
2031 | } |
2032 | |
2033 | /* Fill the dynamic section with tags describing the address and size of |
2034 | sections */ |
2035 | static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) |
2036 | { |
2037 | Section *dynamic = dyninf->dynamic; |
2038 | Section *s; |
2039 | |
2040 | /* put dynamic section entries */ |
2041 | put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
2042 | put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr); |
2043 | put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
2044 | put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset); |
2045 | put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
2046 | #if PTR_SIZE == 8 |
2047 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
2048 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
2049 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
2050 | #else |
2051 | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
2052 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
2053 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); |
2054 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); |
2055 | put_dt(dynamic, DT_PLTREL, DT_REL); |
2056 | put_dt(dynamic, DT_REL, dyninf->bss_addr); |
2057 | put_dt(dynamic, DT_RELSZ, dyninf->bss_size); |
2058 | #else |
2059 | put_dt(dynamic, DT_REL, dyninf->rel_addr); |
2060 | put_dt(dynamic, DT_RELSZ, dyninf->rel_size); |
2061 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
2062 | #endif |
2063 | #endif |
2064 | if (versym_section) |
2065 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); |
2066 | if (verneed_section) { |
2067 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); |
2068 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); |
2069 | } |
2070 | s = find_section_create (s1, ".preinit_array" , 0); |
2071 | if (s && s->data_offset) { |
2072 | put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr); |
2073 | put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset); |
2074 | } |
2075 | s = find_section_create (s1, ".init_array" , 0); |
2076 | if (s && s->data_offset) { |
2077 | put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr); |
2078 | put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset); |
2079 | } |
2080 | s = find_section_create (s1, ".fini_array" , 0); |
2081 | if (s && s->data_offset) { |
2082 | put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr); |
2083 | put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset); |
2084 | } |
2085 | s = find_section_create (s1, ".init" , 0); |
2086 | if (s && s->data_offset) { |
2087 | put_dt(dynamic, DT_INIT, s->sh_addr); |
2088 | } |
2089 | s = find_section_create (s1, ".fini" , 0); |
2090 | if (s && s->data_offset) { |
2091 | put_dt(dynamic, DT_FINI, s->sh_addr); |
2092 | } |
2093 | if (s1->do_debug) |
2094 | put_dt(dynamic, DT_DEBUG, 0); |
2095 | put_dt(dynamic, DT_NULL, 0); |
2096 | } |
2097 | |
2098 | /* Relocate remaining sections and symbols (that is those not related to |
2099 | dynamic linking) */ |
2100 | static int final_sections_reloc(TCCState *s1) |
2101 | { |
2102 | int i; |
2103 | Section *s; |
2104 | |
2105 | relocate_syms(s1, s1->symtab, 0); |
2106 | |
2107 | if (s1->nb_errors != 0) |
2108 | return -1; |
2109 | |
2110 | /* relocate sections */ |
2111 | /* XXX: ignore sections with allocated relocations ? */ |
2112 | for(i = 1; i < s1->nb_sections; i++) { |
2113 | s = s1->sections[i]; |
2114 | if (s->reloc && (s != s1->got || s1->static_link)) |
2115 | relocate_section(s1, s); |
2116 | } |
2117 | |
2118 | /* relocate relocation entries if the relocation tables are |
2119 | allocated in the executable */ |
2120 | for(i = 1; i < s1->nb_sections; i++) { |
2121 | s = s1->sections[i]; |
2122 | if ((s->sh_flags & SHF_ALLOC) && |
2123 | s->sh_type == SHT_RELX) { |
2124 | relocate_rel(s1, s); |
2125 | } |
2126 | } |
2127 | return 0; |
2128 | } |
2129 | #endif |
2130 | |
2131 | /* Create an ELF file on disk. |
2132 | This function handle ELF specific layout requirements */ |
2133 | static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, |
2134 | int file_offset, int *sec_order) |
2135 | { |
2136 | int i, shnum, offset, size, file_type; |
2137 | Section *s; |
2138 | ElfW(Ehdr) ehdr; |
2139 | ElfW(Shdr) shdr, *sh; |
2140 | |
2141 | file_type = s1->output_type; |
2142 | shnum = s1->nb_sections; |
2143 | |
2144 | memset(&ehdr, 0, sizeof(ehdr)); |
2145 | |
2146 | if (phnum > 0) { |
2147 | ehdr.e_phentsize = sizeof(ElfW(Phdr)); |
2148 | ehdr.e_phnum = phnum; |
2149 | ehdr.e_phoff = sizeof(ElfW(Ehdr)); |
2150 | } |
2151 | |
2152 | /* align to 4 */ |
2153 | file_offset = (file_offset + 3) & -4; |
2154 | |
2155 | /* fill header */ |
2156 | ehdr.e_ident[0] = ELFMAG0; |
2157 | ehdr.e_ident[1] = ELFMAG1; |
2158 | ehdr.e_ident[2] = ELFMAG2; |
2159 | ehdr.e_ident[3] = ELFMAG3; |
2160 | ehdr.e_ident[4] = ELFCLASSW; |
2161 | ehdr.e_ident[5] = ELFDATA2LSB; |
2162 | ehdr.e_ident[6] = EV_CURRENT; |
2163 | #if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) |
2164 | /* FIXME: should set only for freebsd _target_, but we exclude only PE target */ |
2165 | ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
2166 | #endif |
2167 | #ifdef TCC_TARGET_ARM |
2168 | #ifdef TCC_ARM_EABI |
2169 | ehdr.e_ident[EI_OSABI] = 0; |
2170 | ehdr.e_flags = EF_ARM_EABI_VER4; |
2171 | if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) |
2172 | ehdr.e_flags |= EF_ARM_HASENTRY; |
2173 | if (s1->float_abi == ARM_HARD_FLOAT) |
2174 | ehdr.e_flags |= EF_ARM_VFP_FLOAT; |
2175 | else |
2176 | ehdr.e_flags |= EF_ARM_SOFT_FLOAT; |
2177 | #else |
2178 | ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
2179 | #endif |
2180 | #elif defined TCC_TARGET_RISCV64 |
2181 | ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE; |
2182 | #endif |
2183 | switch(file_type) { |
2184 | default: |
2185 | case TCC_OUTPUT_EXE: |
2186 | ehdr.e_type = ET_EXEC; |
2187 | ehdr.e_entry = get_sym_addr(s1, "_start" , 1, 0); |
2188 | break; |
2189 | case TCC_OUTPUT_DLL: |
2190 | ehdr.e_type = ET_DYN; |
2191 | ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
2192 | break; |
2193 | case TCC_OUTPUT_OBJ: |
2194 | ehdr.e_type = ET_REL; |
2195 | break; |
2196 | } |
2197 | ehdr.e_machine = EM_TCC_TARGET; |
2198 | ehdr.e_version = EV_CURRENT; |
2199 | ehdr.e_shoff = file_offset; |
2200 | ehdr.e_ehsize = sizeof(ElfW(Ehdr)); |
2201 | ehdr.e_shentsize = sizeof(ElfW(Shdr)); |
2202 | ehdr.e_shnum = shnum; |
2203 | ehdr.e_shstrndx = shnum - 1; |
2204 | |
2205 | fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); |
2206 | fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); |
2207 | offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
2208 | |
2209 | sort_syms(s1, symtab_section); |
2210 | for(i = 1; i < s1->nb_sections; i++) { |
2211 | s = s1->sections[sec_order[i]]; |
2212 | if (s->sh_type != SHT_NOBITS) { |
2213 | while (offset < s->sh_offset) { |
2214 | fputc(0, f); |
2215 | offset++; |
2216 | } |
2217 | size = s->sh_size; |
2218 | if (size) |
2219 | fwrite(s->data, 1, size, f); |
2220 | offset += size; |
2221 | } |
2222 | } |
2223 | |
2224 | /* output section headers */ |
2225 | while (offset < ehdr.e_shoff) { |
2226 | fputc(0, f); |
2227 | offset++; |
2228 | } |
2229 | |
2230 | for(i = 0; i < s1->nb_sections; i++) { |
2231 | sh = &shdr; |
2232 | memset(sh, 0, sizeof(ElfW(Shdr))); |
2233 | s = s1->sections[i]; |
2234 | if (s) { |
2235 | sh->sh_name = s->sh_name; |
2236 | sh->sh_type = s->sh_type; |
2237 | sh->sh_flags = s->sh_flags; |
2238 | sh->sh_entsize = s->sh_entsize; |
2239 | sh->sh_info = s->sh_info; |
2240 | if (s->link) |
2241 | sh->sh_link = s->link->sh_num; |
2242 | sh->sh_addralign = s->sh_addralign; |
2243 | sh->sh_addr = s->sh_addr; |
2244 | sh->sh_offset = s->sh_offset; |
2245 | sh->sh_size = s->sh_size; |
2246 | } |
2247 | fwrite(sh, 1, sizeof(ElfW(Shdr)), f); |
2248 | } |
2249 | } |
2250 | |
2251 | /* Write an elf, coff or "binary" file */ |
2252 | static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum, |
2253 | ElfW(Phdr) *phdr, int file_offset, int *sec_order) |
2254 | { |
2255 | int fd, mode, file_type; |
2256 | FILE *f; |
2257 | |
2258 | file_type = s1->output_type; |
2259 | if (file_type == TCC_OUTPUT_OBJ) |
2260 | mode = 0666; |
2261 | else |
2262 | mode = 0777; |
2263 | unlink(filename); |
2264 | fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
2265 | if (fd < 0) { |
2266 | tcc_error_noabort("could not write '%s'" , filename); |
2267 | return -1; |
2268 | } |
2269 | f = fdopen(fd, "wb" ); |
2270 | if (s1->verbose) |
2271 | printf("<- %s\n" , filename); |
2272 | |
2273 | #ifdef TCC_TARGET_COFF |
2274 | if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) |
2275 | tcc_output_coff(s1, f); |
2276 | else |
2277 | #endif |
2278 | if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) |
2279 | tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order); |
2280 | else |
2281 | tcc_output_binary(s1, f, sec_order); |
2282 | fclose(f); |
2283 | |
2284 | return 0; |
2285 | } |
2286 | |
2287 | #ifndef ELF_OBJ_ONLY |
2288 | /* Sort section headers by assigned sh_addr, remove sections |
2289 | that we aren't going to output. */ |
2290 | static void (TCCState *s1, int *sec_order) |
2291 | { |
2292 | int i, nnew, l, *backmap; |
2293 | Section **snew, *s; |
2294 | ElfW(Sym) *sym; |
2295 | |
2296 | snew = tcc_malloc(s1->nb_sections * sizeof(snew[0])); |
2297 | backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); |
2298 | for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) { |
2299 | s = s1->sections[sec_order[i]]; |
2300 | if (!i || s->sh_name) { |
2301 | backmap[sec_order[i]] = nnew; |
2302 | snew[nnew] = s; |
2303 | ++nnew; |
2304 | } else { |
2305 | backmap[sec_order[i]] = 0; |
2306 | snew[--l] = s; |
2307 | } |
2308 | } |
2309 | for (i = 0; i < nnew; i++) { |
2310 | s = snew[i]; |
2311 | if (s) { |
2312 | s->sh_num = i; |
2313 | if (s->sh_type == SHT_RELX) |
2314 | s->sh_info = backmap[s->sh_info]; |
2315 | } |
2316 | } |
2317 | |
2318 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) |
2319 | if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) |
2320 | sym->st_shndx = backmap[sym->st_shndx]; |
2321 | if ( !s1->static_link ) { |
2322 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) |
2323 | if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) |
2324 | sym->st_shndx = backmap[sym->st_shndx]; |
2325 | } |
2326 | for (i = 0; i < s1->nb_sections; i++) |
2327 | sec_order[i] = i; |
2328 | tcc_free(s1->sections); |
2329 | s1->sections = snew; |
2330 | s1->nb_sections = nnew; |
2331 | tcc_free(backmap); |
2332 | } |
2333 | #endif |
2334 | |
2335 | #ifdef TCC_TARGET_ARM |
2336 | static void create_arm_attribute_section(TCCState *s1) |
2337 | { |
2338 | // Needed for DLL support. |
2339 | static const unsigned char arm_attr[] = { |
2340 | 0x41, // 'A' |
2341 | 0x2c, 0x00, 0x00, 0x00, // size 0x2c |
2342 | 'a', 'e', 'a', 'b', 'i', 0x00, // "aeabi" |
2343 | 0x01, 0x22, 0x00, 0x00, 0x00, // 'File Attributes', size 0x22 |
2344 | 0x05, 0x36, 0x00, // 'CPU_name', "6" |
2345 | 0x06, 0x06, // 'CPU_arch', 'v6' |
2346 | 0x08, 0x01, // 'ARM_ISA_use', 'Yes' |
2347 | 0x09, 0x01, // 'THUMB_ISA_use', 'Thumb-1' |
2348 | 0x0a, 0x02, // 'FP_arch', 'VFPv2' |
2349 | 0x12, 0x04, // 'ABI_PCS_wchar_t', 4 |
2350 | 0x14, 0x01, // 'ABI_FP_denormal', 'Needed' |
2351 | 0x15, 0x01, // 'ABI_FP_exceptions', 'Needed' |
2352 | 0x17, 0x03, // 'ABI_FP_number_model', 'IEEE 754' |
2353 | 0x18, 0x01, // 'ABI_align_needed', '8-byte' |
2354 | 0x19, 0x01, // 'ABI_align_preserved', '8-byte, except leaf SP' |
2355 | 0x1a, 0x02, // 'ABI_enum_size', 'int' |
2356 | 0x1c, 0x01, // 'ABI_VFP_args', 'VFP registers' |
2357 | 0x22, 0x01 // 'CPU_unaligned_access', 'v6' |
2358 | }; |
2359 | Section *attr = new_section(s1, ".ARM.attributes" , SHT_ARM_ATTRIBUTES, 0); |
2360 | unsigned char *ptr = section_ptr_add(attr, sizeof(arm_attr)); |
2361 | attr->sh_addralign = 1; |
2362 | memcpy(ptr, arm_attr, sizeof(arm_attr)); |
2363 | if (s1->float_abi != ARM_HARD_FLOAT) { |
2364 | ptr[26] = 0x00; // 'FP_arch', 'No' |
2365 | ptr[41] = 0x1e; // 'ABI_optimization_goals' |
2366 | ptr[42] = 0x06; // 'Aggressive Debug' |
2367 | } |
2368 | } |
2369 | #endif |
2370 | |
2371 | /* Output an elf, coff or binary file */ |
2372 | /* XXX: suppress unneeded sections */ |
2373 | static int elf_output_file(TCCState *s1, const char *filename) |
2374 | { |
2375 | int ret, phnum, shnum, file_type, file_offset, *sec_order; |
2376 | struct dyn_inf dyninf = {0}; |
2377 | ElfW(Phdr) *phdr; |
2378 | Section *strsec, *interp, *dynamic, *dynstr; |
2379 | |
2380 | #ifdef TCC_TARGET_ARM |
2381 | create_arm_attribute_section (s1); |
2382 | #endif |
2383 | |
2384 | file_type = s1->output_type; |
2385 | s1->nb_errors = 0; |
2386 | ret = -1; |
2387 | phdr = NULL; |
2388 | sec_order = NULL; |
2389 | interp = dynamic = dynstr = NULL; /* avoid warning */ |
2390 | |
2391 | #ifndef ELF_OBJ_ONLY |
2392 | if (file_type != TCC_OUTPUT_OBJ) { |
2393 | /* if linking, also link in runtime libraries (libc, libgcc, etc.) */ |
2394 | tcc_add_runtime(s1); |
2395 | resolve_common_syms(s1); |
2396 | |
2397 | if (!s1->static_link) { |
2398 | if (file_type == TCC_OUTPUT_EXE) { |
2399 | char *ptr; |
2400 | /* allow override the dynamic loader */ |
2401 | const char *elfint = getenv("LD_SO" ); |
2402 | if (elfint == NULL) |
2403 | elfint = DEFAULT_ELFINTERP(s1); |
2404 | /* add interpreter section only if executable */ |
2405 | interp = new_section(s1, ".interp" , SHT_PROGBITS, SHF_ALLOC); |
2406 | interp->sh_addralign = 1; |
2407 | ptr = section_ptr_add(interp, 1 + strlen(elfint)); |
2408 | strcpy(ptr, elfint); |
2409 | } |
2410 | |
2411 | /* add dynamic symbol table */ |
2412 | s1->dynsym = new_symtab(s1, ".dynsym" , SHT_DYNSYM, SHF_ALLOC, |
2413 | ".dynstr" , |
2414 | ".hash" , SHF_ALLOC); |
2415 | dynstr = s1->dynsym->link; |
2416 | /* add dynamic section */ |
2417 | dynamic = new_section(s1, ".dynamic" , SHT_DYNAMIC, |
2418 | SHF_ALLOC | SHF_WRITE); |
2419 | dynamic->link = dynstr; |
2420 | dynamic->sh_entsize = sizeof(ElfW(Dyn)); |
2421 | |
2422 | build_got(s1); |
2423 | |
2424 | if (file_type == TCC_OUTPUT_EXE) { |
2425 | bind_exe_dynsyms(s1); |
2426 | if (s1->nb_errors) |
2427 | goto the_end; |
2428 | bind_libs_dynsyms(s1); |
2429 | } else { |
2430 | /* shared library case: simply export all global symbols */ |
2431 | export_global_syms(s1); |
2432 | } |
2433 | } |
2434 | build_got_entries(s1); |
2435 | version_add (s1); |
2436 | } |
2437 | #endif |
2438 | |
2439 | /* we add a section for symbols */ |
2440 | strsec = new_section(s1, ".shstrtab" , SHT_STRTAB, 0); |
2441 | put_elf_str(strsec, "" ); |
2442 | |
2443 | /* Allocate strings for section names */ |
2444 | ret = alloc_sec_names(s1, file_type, strsec); |
2445 | |
2446 | #ifndef ELF_OBJ_ONLY |
2447 | if (dynamic) { |
2448 | int i; |
2449 | /* add a list of needed dlls */ |
2450 | for(i = 0; i < s1->nb_loaded_dlls; i++) { |
2451 | DLLReference *dllref = s1->loaded_dlls[i]; |
2452 | if (dllref->level == 0) |
2453 | put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
2454 | } |
2455 | |
2456 | if (s1->rpath) |
2457 | put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH, |
2458 | put_elf_str(dynstr, s1->rpath)); |
2459 | |
2460 | if (file_type == TCC_OUTPUT_DLL) { |
2461 | if (s1->soname) |
2462 | put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); |
2463 | /* XXX: currently, since we do not handle PIC code, we |
2464 | must relocate the readonly segments */ |
2465 | if (ret) |
2466 | put_dt(dynamic, DT_TEXTREL, 0); |
2467 | } |
2468 | |
2469 | if (s1->symbolic) |
2470 | put_dt(dynamic, DT_SYMBOLIC, 0); |
2471 | |
2472 | dyninf.dynamic = dynamic; |
2473 | dyninf.dynstr = dynstr; |
2474 | /* remember offset and reserve space for 2nd call below */ |
2475 | dyninf.data_offset = dynamic->data_offset; |
2476 | fill_dynamic(s1, &dyninf); |
2477 | dynamic->sh_size = dynamic->data_offset; |
2478 | dynstr->sh_size = dynstr->data_offset; |
2479 | } |
2480 | #endif |
2481 | |
2482 | /* compute number of program headers */ |
2483 | if (file_type == TCC_OUTPUT_OBJ) |
2484 | phnum = 0; |
2485 | else if (file_type == TCC_OUTPUT_DLL) |
2486 | phnum = 3; |
2487 | else if (s1->static_link) |
2488 | phnum = 2; |
2489 | else { |
2490 | int i; |
2491 | for (i = 1; i < s1->nb_sections && |
2492 | !(s1->sections[i]->sh_flags & SHF_TLS); i++); |
2493 | phnum = i < s1->nb_sections ? 6 : 5; |
2494 | } |
2495 | |
2496 | /* allocate program segment headers */ |
2497 | phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
2498 | |
2499 | /* compute number of sections */ |
2500 | shnum = s1->nb_sections; |
2501 | |
2502 | /* this array is used to reorder sections in the output file */ |
2503 | sec_order = tcc_malloc(sizeof(int) * shnum); |
2504 | sec_order[0] = 0; |
2505 | |
2506 | /* compute section to program header mapping */ |
2507 | file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf, |
2508 | sec_order); |
2509 | |
2510 | #ifndef ELF_OBJ_ONLY |
2511 | /* Fill remaining program header and finalize relocation related to dynamic |
2512 | linking. */ |
2513 | if (file_type != TCC_OUTPUT_OBJ) { |
2514 | fill_unloadable_phdr(phdr, phnum, interp, dynamic); |
2515 | if (dynamic) { |
2516 | ElfW(Sym) *sym; |
2517 | dynamic->data_offset = dyninf.data_offset; |
2518 | fill_dynamic(s1, &dyninf); |
2519 | |
2520 | /* put in GOT the dynamic section address and relocate PLT */ |
2521 | write32le(s1->got->data, dynamic->sh_addr); |
2522 | if (file_type == TCC_OUTPUT_EXE |
2523 | || (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL)) |
2524 | relocate_plt(s1); |
2525 | |
2526 | /* relocate symbols in .dynsym now that final addresses are known */ |
2527 | for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) { |
2528 | if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) { |
2529 | /* do symbol relocation */ |
2530 | sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
2531 | } |
2532 | } |
2533 | } |
2534 | |
2535 | /* if building executable or DLL, then relocate each section |
2536 | except the GOT which is already relocated */ |
2537 | ret = final_sections_reloc(s1); |
2538 | if (ret) |
2539 | goto the_end; |
2540 | tidy_section_headers(s1, sec_order); |
2541 | |
2542 | /* Perform relocation to GOT or PLT entries */ |
2543 | if (file_type == TCC_OUTPUT_EXE && s1->static_link) |
2544 | fill_got(s1); |
2545 | else if (s1->got) |
2546 | fill_local_got_entries(s1); |
2547 | } |
2548 | #endif |
2549 | |
2550 | /* Create the ELF file with name 'filename' */ |
2551 | ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order); |
2552 | s1->nb_sections = shnum; |
2553 | goto the_end; |
2554 | the_end: |
2555 | tcc_free(sec_order); |
2556 | tcc_free(phdr); |
2557 | return ret; |
2558 | } |
2559 | |
2560 | LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) |
2561 | { |
2562 | int ret; |
2563 | #ifdef TCC_TARGET_PE |
2564 | if (s->output_type != TCC_OUTPUT_OBJ) { |
2565 | ret = pe_output_file(s, filename); |
2566 | } else |
2567 | #elif TCC_TARGET_MACHO |
2568 | if (s->output_type != TCC_OUTPUT_OBJ) { |
2569 | ret = macho_output_file(s, filename); |
2570 | } else |
2571 | #endif |
2572 | ret = elf_output_file(s, filename); |
2573 | return ret; |
2574 | } |
2575 | |
2576 | ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) { |
2577 | char *cbuf = buf; |
2578 | size_t rnum = 0; |
2579 | while (1) { |
2580 | ssize_t num = read(fd, cbuf, count-rnum); |
2581 | if (num < 0) return num; |
2582 | if (num == 0) return rnum; |
2583 | rnum += num; |
2584 | cbuf += num; |
2585 | } |
2586 | } |
2587 | |
2588 | ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size) |
2589 | { |
2590 | void *data; |
2591 | |
2592 | data = tcc_malloc(size); |
2593 | lseek(fd, file_offset, SEEK_SET); |
2594 | full_read(fd, data, size); |
2595 | return data; |
2596 | } |
2597 | |
2598 | typedef struct SectionMergeInfo { |
2599 | Section *s; /* corresponding existing section */ |
2600 | unsigned long offset; /* offset of the new section in the existing section */ |
2601 | uint8_t new_section; /* true if section 's' was added */ |
2602 | uint8_t link_once; /* true if link once section */ |
2603 | } SectionMergeInfo; |
2604 | |
2605 | ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h) |
2606 | { |
2607 | int size = full_read(fd, h, sizeof *h); |
2608 | if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) { |
2609 | if (h->e_type == ET_REL) |
2610 | return AFF_BINTYPE_REL; |
2611 | if (h->e_type == ET_DYN) |
2612 | return AFF_BINTYPE_DYN; |
2613 | } else if (size >= 8) { |
2614 | if (0 == memcmp(h, ARMAG, 8)) |
2615 | return AFF_BINTYPE_AR; |
2616 | #ifdef TCC_TARGET_COFF |
2617 | if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC) |
2618 | return AFF_BINTYPE_C67; |
2619 | #endif |
2620 | } |
2621 | return 0; |
2622 | } |
2623 | |
2624 | /* load an object file and merge it with current files */ |
2625 | /* XXX: handle correctly stab (debug) info */ |
2626 | ST_FUNC int tcc_load_object_file(TCCState *s1, |
2627 | int fd, unsigned long file_offset) |
2628 | { |
2629 | ElfW(Ehdr) ehdr; |
2630 | ElfW(Shdr) *shdr, *sh; |
2631 | int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed; |
2632 | char *strsec, *strtab; |
2633 | int stab_index, stabstr_index; |
2634 | int *old_to_new_syms; |
2635 | char *sh_name, *name; |
2636 | SectionMergeInfo *sm_table, *sm; |
2637 | ElfW(Sym) *sym, *symtab; |
2638 | ElfW_Rel *rel; |
2639 | Section *s; |
2640 | |
2641 | lseek(fd, file_offset, SEEK_SET); |
2642 | if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL) |
2643 | goto fail1; |
2644 | /* test CPU specific stuff */ |
2645 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
2646 | ehdr.e_machine != EM_TCC_TARGET) { |
2647 | fail1: |
2648 | tcc_error_noabort("invalid object file" ); |
2649 | return -1; |
2650 | } |
2651 | /* read sections */ |
2652 | shdr = load_data(fd, file_offset + ehdr.e_shoff, |
2653 | sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
2654 | sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
2655 | |
2656 | /* load section names */ |
2657 | sh = &shdr[ehdr.e_shstrndx]; |
2658 | strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
2659 | |
2660 | /* load symtab and strtab */ |
2661 | old_to_new_syms = NULL; |
2662 | symtab = NULL; |
2663 | strtab = NULL; |
2664 | nb_syms = 0; |
2665 | seencompressed = 0; |
2666 | stab_index = stabstr_index = 0; |
2667 | |
2668 | for(i = 1; i < ehdr.e_shnum; i++) { |
2669 | sh = &shdr[i]; |
2670 | if (sh->sh_type == SHT_SYMTAB) { |
2671 | if (symtab) { |
2672 | tcc_error_noabort("object must contain only one symtab" ); |
2673 | fail: |
2674 | ret = -1; |
2675 | goto the_end; |
2676 | } |
2677 | nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
2678 | symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
2679 | sm_table[i].s = symtab_section; |
2680 | |
2681 | /* now load strtab */ |
2682 | sh = &shdr[sh->sh_link]; |
2683 | strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
2684 | } |
2685 | if (sh->sh_flags & SHF_COMPRESSED) |
2686 | seencompressed = 1; |
2687 | } |
2688 | |
2689 | /* now examine each section and try to merge its content with the |
2690 | ones in memory */ |
2691 | for(i = 1; i < ehdr.e_shnum; i++) { |
2692 | /* no need to examine section name strtab */ |
2693 | if (i == ehdr.e_shstrndx) |
2694 | continue; |
2695 | sh = &shdr[i]; |
2696 | if (sh->sh_type == SHT_RELX) |
2697 | sh = &shdr[sh->sh_info]; |
2698 | /* ignore sections types we do not handle (plus relocs to those) */ |
2699 | if (sh->sh_type != SHT_PROGBITS && |
2700 | #ifdef TCC_ARM_EABI |
2701 | sh->sh_type != SHT_ARM_EXIDX && |
2702 | #endif |
2703 | sh->sh_type != SHT_NOBITS && |
2704 | sh->sh_type != SHT_PREINIT_ARRAY && |
2705 | sh->sh_type != SHT_INIT_ARRAY && |
2706 | sh->sh_type != SHT_FINI_ARRAY && |
2707 | strcmp(strsec + sh->sh_name, ".stabstr" ) |
2708 | ) |
2709 | continue; |
2710 | if (seencompressed |
2711 | && !strncmp(strsec + sh->sh_name, ".debug_" , sizeof(".debug_" )-1)) |
2712 | continue; |
2713 | |
2714 | sh = &shdr[i]; |
2715 | sh_name = strsec + sh->sh_name; |
2716 | if (sh->sh_addralign < 1) |
2717 | sh->sh_addralign = 1; |
2718 | /* find corresponding section, if any */ |
2719 | for(j = 1; j < s1->nb_sections;j++) { |
2720 | s = s1->sections[j]; |
2721 | if (!strcmp(s->name, sh_name)) { |
2722 | if (!strncmp(sh_name, ".gnu.linkonce" , |
2723 | sizeof(".gnu.linkonce" ) - 1)) { |
2724 | /* if a 'linkonce' section is already present, we |
2725 | do not add it again. It is a little tricky as |
2726 | symbols can still be defined in |
2727 | it. */ |
2728 | sm_table[i].link_once = 1; |
2729 | goto next; |
2730 | } |
2731 | if (stab_section) { |
2732 | if (s == stab_section) |
2733 | stab_index = i; |
2734 | if (s == stab_section->link) |
2735 | stabstr_index = i; |
2736 | } |
2737 | goto found; |
2738 | } |
2739 | } |
2740 | /* not found: create new section */ |
2741 | s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP); |
2742 | /* take as much info as possible from the section. sh_link and |
2743 | sh_info will be updated later */ |
2744 | s->sh_addralign = sh->sh_addralign; |
2745 | s->sh_entsize = sh->sh_entsize; |
2746 | sm_table[i].new_section = 1; |
2747 | found: |
2748 | if (sh->sh_type != s->sh_type) { |
2749 | tcc_error_noabort("invalid section type" ); |
2750 | goto fail; |
2751 | } |
2752 | /* align start of section */ |
2753 | s->data_offset += -s->data_offset & (sh->sh_addralign - 1); |
2754 | if (sh->sh_addralign > s->sh_addralign) |
2755 | s->sh_addralign = sh->sh_addralign; |
2756 | sm_table[i].offset = s->data_offset; |
2757 | sm_table[i].s = s; |
2758 | /* concatenate sections */ |
2759 | size = sh->sh_size; |
2760 | if (sh->sh_type != SHT_NOBITS) { |
2761 | unsigned char *ptr; |
2762 | lseek(fd, file_offset + sh->sh_offset, SEEK_SET); |
2763 | ptr = section_ptr_add(s, size); |
2764 | full_read(fd, ptr, size); |
2765 | } else { |
2766 | s->data_offset += size; |
2767 | } |
2768 | next: ; |
2769 | } |
2770 | |
2771 | /* gr relocate stab strings */ |
2772 | if (stab_index && stabstr_index) { |
2773 | Stab_Sym *a, *b; |
2774 | unsigned o; |
2775 | s = sm_table[stab_index].s; |
2776 | a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); |
2777 | b = (Stab_Sym *)(s->data + s->data_offset); |
2778 | o = sm_table[stabstr_index].offset; |
2779 | while (a < b) { |
2780 | if (a->n_strx) |
2781 | a->n_strx += o; |
2782 | a++; |
2783 | } |
2784 | } |
2785 | |
2786 | /* second short pass to update sh_link and sh_info fields of new |
2787 | sections */ |
2788 | for(i = 1; i < ehdr.e_shnum; i++) { |
2789 | s = sm_table[i].s; |
2790 | if (!s || !sm_table[i].new_section) |
2791 | continue; |
2792 | sh = &shdr[i]; |
2793 | if (sh->sh_link > 0) |
2794 | s->link = sm_table[sh->sh_link].s; |
2795 | if (sh->sh_type == SHT_RELX) { |
2796 | s->sh_info = sm_table[sh->sh_info].s->sh_num; |
2797 | /* update backward link */ |
2798 | s1->sections[s->sh_info]->reloc = s; |
2799 | } |
2800 | } |
2801 | |
2802 | /* resolve symbols */ |
2803 | old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); |
2804 | |
2805 | sym = symtab + 1; |
2806 | for(i = 1; i < nb_syms; i++, sym++) { |
2807 | if (sym->st_shndx != SHN_UNDEF && |
2808 | sym->st_shndx < SHN_LORESERVE) { |
2809 | sm = &sm_table[sym->st_shndx]; |
2810 | if (sm->link_once) { |
2811 | /* if a symbol is in a link once section, we use the |
2812 | already defined symbol. It is very important to get |
2813 | correct relocations */ |
2814 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
2815 | name = strtab + sym->st_name; |
2816 | sym_index = find_elf_sym(symtab_section, name); |
2817 | if (sym_index) |
2818 | old_to_new_syms[i] = sym_index; |
2819 | } |
2820 | continue; |
2821 | } |
2822 | /* if no corresponding section added, no need to add symbol */ |
2823 | if (!sm->s) |
2824 | continue; |
2825 | /* convert section number */ |
2826 | sym->st_shndx = sm->s->sh_num; |
2827 | /* offset value */ |
2828 | sym->st_value += sm->offset; |
2829 | } |
2830 | /* add symbol */ |
2831 | name = strtab + sym->st_name; |
2832 | sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size, |
2833 | sym->st_info, sym->st_other, |
2834 | sym->st_shndx, name); |
2835 | old_to_new_syms[i] = sym_index; |
2836 | } |
2837 | |
2838 | /* third pass to patch relocation entries */ |
2839 | for(i = 1; i < ehdr.e_shnum; i++) { |
2840 | s = sm_table[i].s; |
2841 | if (!s) |
2842 | continue; |
2843 | sh = &shdr[i]; |
2844 | offset = sm_table[i].offset; |
2845 | switch(s->sh_type) { |
2846 | case SHT_RELX: |
2847 | /* take relocation offset information */ |
2848 | offseti = sm_table[sh->sh_info].offset; |
2849 | for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) { |
2850 | int type; |
2851 | unsigned sym_index; |
2852 | /* convert symbol index */ |
2853 | type = ELFW(R_TYPE)(rel->r_info); |
2854 | sym_index = ELFW(R_SYM)(rel->r_info); |
2855 | /* NOTE: only one symtab assumed */ |
2856 | if (sym_index >= nb_syms) |
2857 | goto invalid_reloc; |
2858 | sym_index = old_to_new_syms[sym_index]; |
2859 | /* ignore link_once in rel section. */ |
2860 | if (!sym_index && !sm_table[sh->sh_info].link_once |
2861 | #ifdef TCC_TARGET_ARM |
2862 | && type != R_ARM_V4BX |
2863 | #elif defined TCC_TARGET_RISCV64 |
2864 | && type != R_RISCV_ALIGN |
2865 | && type != R_RISCV_RELAX |
2866 | #endif |
2867 | ) { |
2868 | invalid_reloc: |
2869 | tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x" , |
2870 | i, strsec + sh->sh_name, (int)rel->r_offset); |
2871 | goto fail; |
2872 | } |
2873 | rel->r_info = ELFW(R_INFO)(sym_index, type); |
2874 | /* offset the relocation offset */ |
2875 | rel->r_offset += offseti; |
2876 | #ifdef TCC_TARGET_ARM |
2877 | /* Jumps and branches from a Thumb code to a PLT entry need |
2878 | special handling since PLT entries are ARM code. |
2879 | Unconditional bl instructions referencing PLT entries are |
2880 | handled by converting these instructions into blx |
2881 | instructions. Other case of instructions referencing a PLT |
2882 | entry require to add a Thumb stub before the PLT entry to |
2883 | switch to ARM mode. We set bit plt_thumb_stub of the |
2884 | attribute of a symbol to indicate such a case. */ |
2885 | if (type == R_ARM_THM_JUMP24) |
2886 | get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1; |
2887 | #endif |
2888 | } |
2889 | break; |
2890 | default: |
2891 | break; |
2892 | } |
2893 | } |
2894 | |
2895 | ret = 0; |
2896 | the_end: |
2897 | tcc_free(symtab); |
2898 | tcc_free(strtab); |
2899 | tcc_free(old_to_new_syms); |
2900 | tcc_free(sm_table); |
2901 | tcc_free(strsec); |
2902 | tcc_free(shdr); |
2903 | return ret; |
2904 | } |
2905 | |
2906 | typedef struct { |
2907 | char [16]; /* name of this member */ |
2908 | char [12]; /* file mtime */ |
2909 | char [6]; /* owner uid; printed as decimal */ |
2910 | char [6]; /* owner gid; printed as decimal */ |
2911 | char [8]; /* file mode, printed as octal */ |
2912 | char [10]; /* file size, printed as decimal */ |
2913 | char [2]; /* should contain ARFMAG */ |
2914 | } ; |
2915 | |
2916 | #define ARFMAG "`\n" |
2917 | |
2918 | static unsigned long long get_be(const uint8_t *b, int n) |
2919 | { |
2920 | unsigned long long ret = 0; |
2921 | while (n) |
2922 | ret = (ret << 8) | *b++, --n; |
2923 | return ret; |
2924 | } |
2925 | |
2926 | static int (int fd, int offset, ArchiveHeader *hdr) |
2927 | { |
2928 | char *p, *e; |
2929 | int len; |
2930 | lseek(fd, offset, SEEK_SET); |
2931 | len = full_read(fd, hdr, sizeof(ArchiveHeader)); |
2932 | if (len != sizeof(ArchiveHeader)) |
2933 | return len ? -1 : 0; |
2934 | p = hdr->ar_name; |
2935 | for (e = p + sizeof hdr->ar_name; e > p && e[-1] == ' ';) |
2936 | --e; |
2937 | *e = '\0'; |
2938 | hdr->ar_size[sizeof hdr->ar_size-1] = 0; |
2939 | return len; |
2940 | } |
2941 | |
2942 | /* load only the objects which resolve undefined symbols */ |
2943 | static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize) |
2944 | { |
2945 | int i, bound, nsyms, sym_index, len, ret = -1; |
2946 | unsigned long long off; |
2947 | uint8_t *data; |
2948 | const char *ar_names, *p; |
2949 | const uint8_t *ar_index; |
2950 | ElfW(Sym) *sym; |
2951 | ArchiveHeader hdr; |
2952 | |
2953 | data = tcc_malloc(size); |
2954 | if (full_read(fd, data, size) != size) |
2955 | goto the_end; |
2956 | nsyms = get_be(data, entrysize); |
2957 | ar_index = data + entrysize; |
2958 | ar_names = (char *) ar_index + nsyms * entrysize; |
2959 | |
2960 | do { |
2961 | bound = 0; |
2962 | for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { |
2963 | Section *s = symtab_section; |
2964 | sym_index = find_elf_sym(s, p); |
2965 | if (!sym_index) |
2966 | continue; |
2967 | sym = &((ElfW(Sym) *)s->data)[sym_index]; |
2968 | if(sym->st_shndx != SHN_UNDEF) |
2969 | continue; |
2970 | off = get_be(ar_index + i * entrysize, entrysize); |
2971 | len = read_ar_header(fd, off, &hdr); |
2972 | if (len <= 0 || memcmp(hdr.ar_fmag, ARFMAG, 2)) { |
2973 | tcc_error_noabort("invalid archive" ); |
2974 | goto the_end; |
2975 | } |
2976 | off += len; |
2977 | if (s1->verbose == 2) |
2978 | printf(" -> %s\n" , hdr.ar_name); |
2979 | if (tcc_load_object_file(s1, fd, off) < 0) |
2980 | goto the_end; |
2981 | ++bound; |
2982 | } |
2983 | } while(bound); |
2984 | ret = 0; |
2985 | the_end: |
2986 | tcc_free(data); |
2987 | return ret; |
2988 | } |
2989 | |
2990 | /* load a '.a' file */ |
2991 | ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte) |
2992 | { |
2993 | ArchiveHeader hdr; |
2994 | /* char magic[8]; */ |
2995 | int size, len; |
2996 | unsigned long file_offset; |
2997 | ElfW(Ehdr) ehdr; |
2998 | |
2999 | /* skip magic which was already checked */ |
3000 | /* full_read(fd, magic, sizeof(magic)); */ |
3001 | file_offset = sizeof ARMAG - 1; |
3002 | |
3003 | for(;;) { |
3004 | len = read_ar_header(fd, file_offset, &hdr); |
3005 | if (len == 0) |
3006 | return 0; |
3007 | if (len < 0) { |
3008 | tcc_error_noabort("invalid archive" ); |
3009 | return -1; |
3010 | } |
3011 | file_offset += len; |
3012 | size = strtol(hdr.ar_size, NULL, 0); |
3013 | /* align to even */ |
3014 | size = (size + 1) & ~1; |
3015 | if (alacarte) { |
3016 | /* coff symbol table : we handle it */ |
3017 | if (!strcmp(hdr.ar_name, "/" )) |
3018 | return tcc_load_alacarte(s1, fd, size, 4); |
3019 | if (!strcmp(hdr.ar_name, "/SYM64/" )) |
3020 | return tcc_load_alacarte(s1, fd, size, 8); |
3021 | } else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) { |
3022 | if (s1->verbose == 2) |
3023 | printf(" -> %s\n" , hdr.ar_name); |
3024 | if (tcc_load_object_file(s1, fd, file_offset) < 0) |
3025 | return -1; |
3026 | } |
3027 | file_offset += size; |
3028 | } |
3029 | } |
3030 | |
3031 | #ifndef ELF_OBJ_ONLY |
3032 | /* Set LV[I] to the global index of sym-version (LIB,VERSION). Maybe resizes |
3033 | LV, maybe create a new entry for (LIB,VERSION). */ |
3034 | static void set_ver_to_ver(TCCState *s1, int *n, int **lv, int i, char *lib, char *version) |
3035 | { |
3036 | while (i >= *n) { |
3037 | *lv = tcc_realloc(*lv, (*n + 1) * sizeof(**lv)); |
3038 | (*lv)[(*n)++] = -1; |
3039 | } |
3040 | if ((*lv)[i] == -1) { |
3041 | int v, prev_same_lib = -1; |
3042 | for (v = 0; v < nb_sym_versions; v++) { |
3043 | if (strcmp(sym_versions[v].lib, lib)) |
3044 | continue; |
3045 | prev_same_lib = v; |
3046 | if (!strcmp(sym_versions[v].version, version)) |
3047 | break; |
3048 | } |
3049 | if (v == nb_sym_versions) { |
3050 | sym_versions = tcc_realloc (sym_versions, |
3051 | (v + 1) * sizeof(*sym_versions)); |
3052 | sym_versions[v].lib = tcc_strdup(lib); |
3053 | sym_versions[v].version = tcc_strdup(version); |
3054 | sym_versions[v].out_index = 0; |
3055 | sym_versions[v].prev_same_lib = prev_same_lib; |
3056 | nb_sym_versions++; |
3057 | } |
3058 | (*lv)[i] = v; |
3059 | } |
3060 | } |
3061 | |
3062 | /* Associates symbol SYM_INDEX (in dynsymtab) with sym-version index |
3063 | VERNDX. */ |
3064 | static void |
3065 | set_sym_version(TCCState *s1, int sym_index, int verndx) |
3066 | { |
3067 | if (sym_index >= nb_sym_to_version) { |
3068 | int newelems = sym_index ? sym_index * 2 : 1; |
3069 | sym_to_version = tcc_realloc(sym_to_version, |
3070 | newelems * sizeof(*sym_to_version)); |
3071 | memset(sym_to_version + nb_sym_to_version, -1, |
3072 | (newelems - nb_sym_to_version) * sizeof(*sym_to_version)); |
3073 | nb_sym_to_version = newelems; |
3074 | } |
3075 | if (sym_to_version[sym_index] < 0) |
3076 | sym_to_version[sym_index] = verndx; |
3077 | } |
3078 | |
3079 | struct versym_info { |
3080 | int nb_versyms; |
3081 | ElfW(Verdef) *verdef; |
3082 | ElfW(Verneed) *verneed; |
3083 | ElfW(Half) *versym; |
3084 | int nb_local_ver, *local_ver; |
3085 | }; |
3086 | |
3087 | |
3088 | static void store_version(TCCState *s1, struct versym_info *v, char *dynstr) |
3089 | { |
3090 | char *lib, *version; |
3091 | uint32_t next; |
3092 | int i; |
3093 | |
3094 | #define DEBUG_VERSION 0 |
3095 | |
3096 | if (v->versym && v->verdef) { |
3097 | ElfW(Verdef) *vdef = v->verdef; |
3098 | lib = NULL; |
3099 | do { |
3100 | ElfW(Verdaux) *verdaux = |
3101 | (ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux); |
3102 | |
3103 | #if DEBUG_VERSION |
3104 | printf ("verdef: version:%u flags:%u index:%u, hash:%u\n" , |
3105 | vdef->vd_version, vdef->vd_flags, vdef->vd_ndx, |
3106 | vdef->vd_hash); |
3107 | #endif |
3108 | if (vdef->vd_cnt) { |
3109 | version = dynstr + verdaux->vda_name; |
3110 | |
3111 | if (lib == NULL) |
3112 | lib = version; |
3113 | else |
3114 | set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vdef->vd_ndx, |
3115 | lib, version); |
3116 | #if DEBUG_VERSION |
3117 | printf (" verdaux(%u): %s\n" , vdef->vd_ndx, version); |
3118 | #endif |
3119 | } |
3120 | next = vdef->vd_next; |
3121 | vdef = (ElfW(Verdef) *) (((char *) vdef) + next); |
3122 | } while (next); |
3123 | } |
3124 | if (v->versym && v->verneed) { |
3125 | ElfW(Verneed) *vneed = v->verneed; |
3126 | do { |
3127 | ElfW(Vernaux) *vernaux = |
3128 | (ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux); |
3129 | |
3130 | lib = dynstr + vneed->vn_file; |
3131 | #if DEBUG_VERSION |
3132 | printf ("verneed: %u %s\n" , vneed->vn_version, lib); |
3133 | #endif |
3134 | for (i = 0; i < vneed->vn_cnt; i++) { |
3135 | if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */ |
3136 | version = dynstr + vernaux->vna_name; |
3137 | set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vernaux->vna_other, |
3138 | lib, version); |
3139 | #if DEBUG_VERSION |
3140 | printf (" vernaux(%u): %u %u %s\n" , |
3141 | vernaux->vna_other, vernaux->vna_hash, |
3142 | vernaux->vna_flags, version); |
3143 | #endif |
3144 | } |
3145 | vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next); |
3146 | } |
3147 | next = vneed->vn_next; |
3148 | vneed = (ElfW(Verneed) *) (((char *) vneed) + next); |
3149 | } while (next); |
3150 | } |
3151 | |
3152 | #if DEBUG_VERSION |
3153 | for (i = 0; i < v->nb_local_ver; i++) { |
3154 | if (v->local_ver[i] > 0) { |
3155 | printf ("%d: lib: %s, version %s\n" , |
3156 | i, sym_versions[v->local_ver[i]].lib, |
3157 | sym_versions[v->local_ver[i]].version); |
3158 | } |
3159 | } |
3160 | #endif |
3161 | } |
3162 | |
3163 | /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL |
3164 | is referenced by the user (so it should be added as DT_NEEDED in |
3165 | the generated ELF file) */ |
3166 | ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
3167 | { |
3168 | ElfW(Ehdr) ehdr; |
3169 | ElfW(Shdr) *shdr, *sh, *sh1; |
3170 | int i, j, nb_syms, nb_dts, sym_bind, ret; |
3171 | ElfW(Sym) *sym, *dynsym; |
3172 | ElfW(Dyn) *dt, *dynamic; |
3173 | |
3174 | char *dynstr; |
3175 | int sym_index; |
3176 | const char *name, *soname; |
3177 | DLLReference *dllref; |
3178 | struct versym_info v; |
3179 | |
3180 | full_read(fd, &ehdr, sizeof(ehdr)); |
3181 | |
3182 | /* test CPU specific stuff */ |
3183 | if (ehdr.e_ident[5] != ELFDATA2LSB || |
3184 | ehdr.e_machine != EM_TCC_TARGET) { |
3185 | tcc_error_noabort("bad architecture" ); |
3186 | return -1; |
3187 | } |
3188 | |
3189 | /* read sections */ |
3190 | shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
3191 | |
3192 | /* load dynamic section and dynamic symbols */ |
3193 | nb_syms = 0; |
3194 | nb_dts = 0; |
3195 | dynamic = NULL; |
3196 | dynsym = NULL; /* avoid warning */ |
3197 | dynstr = NULL; /* avoid warning */ |
3198 | memset(&v, 0, sizeof v); |
3199 | |
3200 | for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { |
3201 | switch(sh->sh_type) { |
3202 | case SHT_DYNAMIC: |
3203 | nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); |
3204 | dynamic = load_data(fd, sh->sh_offset, sh->sh_size); |
3205 | break; |
3206 | case SHT_DYNSYM: |
3207 | nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
3208 | dynsym = load_data(fd, sh->sh_offset, sh->sh_size); |
3209 | sh1 = &shdr[sh->sh_link]; |
3210 | dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); |
3211 | break; |
3212 | case SHT_GNU_verdef: |
3213 | v.verdef = load_data(fd, sh->sh_offset, sh->sh_size); |
3214 | break; |
3215 | case SHT_GNU_verneed: |
3216 | v.verneed = load_data(fd, sh->sh_offset, sh->sh_size); |
3217 | break; |
3218 | case SHT_GNU_versym: |
3219 | v.nb_versyms = sh->sh_size / sizeof(ElfW(Half)); |
3220 | v.versym = load_data(fd, sh->sh_offset, sh->sh_size); |
3221 | break; |
3222 | default: |
3223 | break; |
3224 | } |
3225 | } |
3226 | |
3227 | /* compute the real library name */ |
3228 | soname = tcc_basename(filename); |
3229 | |
3230 | for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
3231 | if (dt->d_tag == DT_SONAME) { |
3232 | soname = dynstr + dt->d_un.d_val; |
3233 | } |
3234 | } |
3235 | |
3236 | /* if the dll is already loaded, do not load it */ |
3237 | for(i = 0; i < s1->nb_loaded_dlls; i++) { |
3238 | dllref = s1->loaded_dlls[i]; |
3239 | if (!strcmp(soname, dllref->name)) { |
3240 | /* but update level if needed */ |
3241 | if (level < dllref->level) |
3242 | dllref->level = level; |
3243 | ret = 0; |
3244 | goto the_end; |
3245 | } |
3246 | } |
3247 | |
3248 | if (v.nb_versyms != nb_syms) |
3249 | tcc_free (v.versym), v.versym = NULL; |
3250 | else |
3251 | store_version(s1, &v, dynstr); |
3252 | |
3253 | /* add the dll and its level */ |
3254 | dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); |
3255 | dllref->level = level; |
3256 | strcpy(dllref->name, soname); |
3257 | dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
3258 | |
3259 | /* add dynamic symbols in dynsym_section */ |
3260 | for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { |
3261 | sym_bind = ELFW(ST_BIND)(sym->st_info); |
3262 | if (sym_bind == STB_LOCAL) |
3263 | continue; |
3264 | name = dynstr + sym->st_name; |
3265 | sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
3266 | sym->st_info, sym->st_other, sym->st_shndx, name); |
3267 | if (v.versym) { |
3268 | ElfW(Half) vsym = v.versym[i]; |
3269 | if ((vsym & 0x8000) == 0 && vsym > 0 && vsym < v.nb_local_ver) |
3270 | set_sym_version(s1, sym_index, v.local_ver[vsym]); |
3271 | } |
3272 | } |
3273 | |
3274 | /* load all referenced DLLs */ |
3275 | for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
3276 | switch(dt->d_tag) { |
3277 | case DT_NEEDED: |
3278 | name = dynstr + dt->d_un.d_val; |
3279 | for(j = 0; j < s1->nb_loaded_dlls; j++) { |
3280 | dllref = s1->loaded_dlls[j]; |
3281 | if (!strcmp(name, dllref->name)) |
3282 | goto already_loaded; |
3283 | } |
3284 | if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
3285 | tcc_error_noabort("referenced dll '%s' not found" , name); |
3286 | ret = -1; |
3287 | goto the_end; |
3288 | } |
3289 | already_loaded: |
3290 | break; |
3291 | } |
3292 | } |
3293 | ret = 0; |
3294 | the_end: |
3295 | tcc_free(dynstr); |
3296 | tcc_free(dynsym); |
3297 | tcc_free(dynamic); |
3298 | tcc_free(shdr); |
3299 | tcc_free(v.local_ver); |
3300 | tcc_free(v.verdef); |
3301 | tcc_free(v.verneed); |
3302 | tcc_free(v.versym); |
3303 | return ret; |
3304 | } |
3305 | |
3306 | #define LD_TOK_NAME 256 |
3307 | #define LD_TOK_EOF (-1) |
3308 | |
3309 | static int ld_inp(TCCState *s1) |
3310 | { |
3311 | char b; |
3312 | if (s1->cc != -1) { |
3313 | int c = s1->cc; |
3314 | s1->cc = -1; |
3315 | return c; |
3316 | } |
3317 | if (1 == read(s1->fd, &b, 1)) |
3318 | return b; |
3319 | return CH_EOF; |
3320 | } |
3321 | |
3322 | /* return next ld script token */ |
3323 | static int ld_next(TCCState *s1, char *name, int name_size) |
3324 | { |
3325 | int c, d, ch; |
3326 | char *q; |
3327 | |
3328 | redo: |
3329 | ch = ld_inp(s1); |
3330 | switch(ch) { |
3331 | case ' ': |
3332 | case '\t': |
3333 | case '\f': |
3334 | case '\v': |
3335 | case '\r': |
3336 | case '\n': |
3337 | goto redo; |
3338 | case '/': |
3339 | ch = ld_inp(s1); |
3340 | if (ch == '*') { /* comment */ |
3341 | for (d = 0;; d = ch) { |
3342 | ch = ld_inp(s1); |
3343 | if (ch == CH_EOF || (ch == '/' && d == '*')) |
3344 | break; |
3345 | } |
3346 | goto redo; |
3347 | } else { |
3348 | q = name; |
3349 | *q++ = '/'; |
3350 | goto parse_name; |
3351 | } |
3352 | break; |
3353 | case '\\': |
3354 | /* case 'a' ... 'z': */ |
3355 | case 'a': |
3356 | case 'b': |
3357 | case 'c': |
3358 | case 'd': |
3359 | case 'e': |
3360 | case 'f': |
3361 | case 'g': |
3362 | case 'h': |
3363 | case 'i': |
3364 | case 'j': |
3365 | case 'k': |
3366 | case 'l': |
3367 | case 'm': |
3368 | case 'n': |
3369 | case 'o': |
3370 | case 'p': |
3371 | case 'q': |
3372 | case 'r': |
3373 | case 's': |
3374 | case 't': |
3375 | case 'u': |
3376 | case 'v': |
3377 | case 'w': |
3378 | case 'x': |
3379 | case 'y': |
3380 | case 'z': |
3381 | /* case 'A' ... 'z': */ |
3382 | case 'A': |
3383 | case 'B': |
3384 | case 'C': |
3385 | case 'D': |
3386 | case 'E': |
3387 | case 'F': |
3388 | case 'G': |
3389 | case 'H': |
3390 | case 'I': |
3391 | case 'J': |
3392 | case 'K': |
3393 | case 'L': |
3394 | case 'M': |
3395 | case 'N': |
3396 | case 'O': |
3397 | case 'P': |
3398 | case 'Q': |
3399 | case 'R': |
3400 | case 'S': |
3401 | case 'T': |
3402 | case 'U': |
3403 | case 'V': |
3404 | case 'W': |
3405 | case 'X': |
3406 | case 'Y': |
3407 | case 'Z': |
3408 | case '_': |
3409 | case '.': |
3410 | case '$': |
3411 | case '~': |
3412 | q = name; |
3413 | parse_name: |
3414 | for(;;) { |
3415 | if (!((ch >= 'a' && ch <= 'z') || |
3416 | (ch >= 'A' && ch <= 'Z') || |
3417 | (ch >= '0' && ch <= '9') || |
3418 | strchr("/.-_+=$:\\,~" , ch))) |
3419 | break; |
3420 | if ((q - name) < name_size - 1) { |
3421 | *q++ = ch; |
3422 | } |
3423 | ch = ld_inp(s1); |
3424 | } |
3425 | s1->cc = ch; |
3426 | *q = '\0'; |
3427 | c = LD_TOK_NAME; |
3428 | break; |
3429 | case CH_EOF: |
3430 | c = LD_TOK_EOF; |
3431 | break; |
3432 | default: |
3433 | c = ch; |
3434 | break; |
3435 | } |
3436 | return c; |
3437 | } |
3438 | |
3439 | static int ld_add_file(TCCState *s1, const char filename[]) |
3440 | { |
3441 | if (filename[0] == '/') { |
3442 | if (CONFIG_SYSROOT[0] == '\0' |
3443 | && tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0) |
3444 | return 0; |
3445 | filename = tcc_basename(filename); |
3446 | } |
3447 | return tcc_add_dll(s1, filename, 0); |
3448 | } |
3449 | |
3450 | static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) |
3451 | { |
3452 | char filename[1024], libname[1024]; |
3453 | int t, group, nblibs = 0, ret = 0; |
3454 | char **libs = NULL; |
3455 | |
3456 | group = !strcmp(cmd, "GROUP" ); |
3457 | if (!as_needed) |
3458 | s1->new_undef_sym = 0; |
3459 | t = ld_next(s1, filename, sizeof(filename)); |
3460 | if (t != '(') { |
3461 | tcc_error_noabort("( expected" ); |
3462 | ret = -1; |
3463 | goto lib_parse_error; |
3464 | } |
3465 | t = ld_next(s1, filename, sizeof(filename)); |
3466 | for(;;) { |
3467 | libname[0] = '\0'; |
3468 | if (t == LD_TOK_EOF) { |
3469 | tcc_error_noabort("unexpected end of file" ); |
3470 | ret = -1; |
3471 | goto lib_parse_error; |
3472 | } else if (t == ')') { |
3473 | break; |
3474 | } else if (t == '-') { |
3475 | t = ld_next(s1, filename, sizeof(filename)); |
3476 | if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { |
3477 | tcc_error_noabort("library name expected" ); |
3478 | ret = -1; |
3479 | goto lib_parse_error; |
3480 | } |
3481 | pstrcpy(libname, sizeof libname, &filename[1]); |
3482 | if (s1->static_link) { |
3483 | snprintf(filename, sizeof filename, "lib%s.a" , libname); |
3484 | } else { |
3485 | snprintf(filename, sizeof filename, "lib%s.so" , libname); |
3486 | } |
3487 | } else if (t != LD_TOK_NAME) { |
3488 | tcc_error_noabort("filename expected" ); |
3489 | ret = -1; |
3490 | goto lib_parse_error; |
3491 | } |
3492 | if (!strcmp(filename, "AS_NEEDED" )) { |
3493 | ret = ld_add_file_list(s1, cmd, 1); |
3494 | if (ret) |
3495 | goto lib_parse_error; |
3496 | } else { |
3497 | /* TODO: Implement AS_NEEDED support. Ignore it for now */ |
3498 | if (!as_needed) { |
3499 | ret = ld_add_file(s1, filename); |
3500 | if (ret) |
3501 | goto lib_parse_error; |
3502 | if (group) { |
3503 | /* Add the filename *and* the libname to avoid future conversions */ |
3504 | dynarray_add(&libs, &nblibs, tcc_strdup(filename)); |
3505 | if (libname[0] != '\0') |
3506 | dynarray_add(&libs, &nblibs, tcc_strdup(libname)); |
3507 | } |
3508 | } |
3509 | } |
3510 | t = ld_next(s1, filename, sizeof(filename)); |
3511 | if (t == ',') { |
3512 | t = ld_next(s1, filename, sizeof(filename)); |
3513 | } |
3514 | } |
3515 | if (group && !as_needed) { |
3516 | while (s1->new_undef_sym) { |
3517 | int i; |
3518 | s1->new_undef_sym = 0; |
3519 | for (i = 0; i < nblibs; i ++) |
3520 | ld_add_file(s1, libs[i]); |
3521 | } |
3522 | } |
3523 | lib_parse_error: |
3524 | dynarray_reset(&libs, &nblibs); |
3525 | return ret; |
3526 | } |
3527 | |
3528 | /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
3529 | files */ |
3530 | ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd) |
3531 | { |
3532 | char cmd[64]; |
3533 | char filename[1024]; |
3534 | int t, ret; |
3535 | |
3536 | s1->fd = fd; |
3537 | s1->cc = -1; |
3538 | for(;;) { |
3539 | t = ld_next(s1, cmd, sizeof(cmd)); |
3540 | if (t == LD_TOK_EOF) |
3541 | return 0; |
3542 | else if (t != LD_TOK_NAME) |
3543 | return -1; |
3544 | if (!strcmp(cmd, "INPUT" ) || |
3545 | !strcmp(cmd, "GROUP" )) { |
3546 | ret = ld_add_file_list(s1, cmd, 0); |
3547 | if (ret) |
3548 | return ret; |
3549 | } else if (!strcmp(cmd, "OUTPUT_FORMAT" ) || |
3550 | !strcmp(cmd, "TARGET" )) { |
3551 | /* ignore some commands */ |
3552 | t = ld_next(s1, cmd, sizeof(cmd)); |
3553 | if (t != '(') { |
3554 | tcc_error_noabort("( expected" ); |
3555 | return -1; |
3556 | } |
3557 | for(;;) { |
3558 | t = ld_next(s1, filename, sizeof(filename)); |
3559 | if (t == LD_TOK_EOF) { |
3560 | tcc_error_noabort("unexpected end of file" ); |
3561 | return -1; |
3562 | } else if (t == ')') { |
3563 | break; |
3564 | } |
3565 | } |
3566 | } else { |
3567 | return -1; |
3568 | } |
3569 | } |
3570 | return 0; |
3571 | } |
3572 | #endif /* !ELF_OBJ_ONLY */ |
3573 | |