Mercurial > hg > qcc
annotate tccelf.c @ 564:d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
author | Rob Landley <rob@landley.net> |
---|---|
date | Tue, 11 Mar 2008 23:45:07 -0500 |
parents | 646f1f0972b6 |
children | c42c2145d359 |
rev | line source |
---|---|
140 | 1 /* |
2 * ELF file handling for TCC | |
3 * | |
331 | 4 * Copyright (c) 2001-2004 Fabrice Bellard |
140 | 5 * |
499
2b451d2e68ea
Exercise LGPL clause 3 and convert more notices from LGPL to GPLv2. (If you
Rob Landley <rob@landley.net>
parents:
481
diff
changeset
|
6 * Licensed under GPLv2, see file LICENSE in this tarball. |
140 | 7 */ |
8 | |
469
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
9 #include <limits.h> |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
10 |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
11 static int put_elf_str(Section *s, char *sym) |
140 | 12 { |
13 int offset, len; | |
14 char *ptr; | |
15 | |
16 len = strlen(sym) + 1; | |
17 offset = s->data_offset; | |
18 ptr = section_ptr_add(s, len); | |
19 memcpy(ptr, sym, len); | |
20 return offset; | |
21 } | |
22 | |
23 /* elf symbol hashing function */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
24 static unsigned long elf_hash(unsigned char *name) |
140 | 25 { |
26 unsigned long h = 0, g; | |
27 | |
28 while (*name) { | |
29 h = (h << 4) + *name++; | |
30 g = h & 0xf0000000; | |
31 if (g) | |
32 h ^= g >> 24; | |
33 h &= ~g; | |
34 } | |
35 return h; | |
36 } | |
37 | |
38 /* rebuild hash table of section s */ | |
39 /* NOTE: we do factorize the hash table code to go faster */ | |
40 static void rebuild_hash(Section *s, unsigned int nb_buckets) | |
41 { | |
42 Elf32_Sym *sym; | |
43 int *ptr, *hash, nb_syms, sym_index, h; | |
44 char *strtab; | |
45 | |
46 strtab = s->link->data; | |
47 nb_syms = s->data_offset / sizeof(Elf32_Sym); | |
48 | |
49 s->hash->data_offset = 0; | |
50 ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); | |
51 ptr[0] = nb_buckets; | |
52 ptr[1] = nb_syms; | |
53 ptr += 2; | |
54 hash = ptr; | |
55 memset(hash, 0, (nb_buckets + 1) * sizeof(int)); | |
56 ptr += nb_buckets + 1; | |
57 | |
58 sym = (Elf32_Sym *)s->data + 1; | |
59 for(sym_index = 1; sym_index < nb_syms; sym_index++) { | |
60 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { | |
61 h = elf_hash(strtab + sym->st_name) % nb_buckets; | |
62 *ptr = hash[h]; | |
63 hash[h] = sym_index; | |
64 } else { | |
65 *ptr = 0; | |
66 } | |
67 ptr++; | |
68 sym++; | |
69 } | |
70 } | |
71 | |
72 /* return the symbol number */ | |
73 static int put_elf_sym(Section *s, | |
74 unsigned long value, unsigned long size, | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
75 int info, int other, int shndx, char *name) |
140 | 76 { |
77 int name_offset, sym_index; | |
78 int nbuckets, h; | |
79 Elf32_Sym *sym; | |
80 Section *hs; | |
81 | |
82 sym = section_ptr_add(s, sizeof(Elf32_Sym)); | |
83 if (name) | |
84 name_offset = put_elf_str(s->link, name); | |
85 else | |
86 name_offset = 0; | |
87 /* XXX: endianness */ | |
88 sym->st_name = name_offset; | |
89 sym->st_value = value; | |
90 sym->st_size = size; | |
91 sym->st_info = info; | |
92 sym->st_other = other; | |
93 sym->st_shndx = shndx; | |
94 sym_index = sym - (Elf32_Sym *)s->data; | |
95 hs = s->hash; | |
96 if (hs) { | |
97 int *ptr, *base; | |
98 ptr = section_ptr_add(hs, sizeof(int)); | |
99 base = (int *)hs->data; | |
100 /* only add global or weak symbols */ | |
101 if (ELF32_ST_BIND(info) != STB_LOCAL) { | |
102 /* add another hashing entry */ | |
103 nbuckets = base[0]; | |
104 h = elf_hash(name) % nbuckets; | |
105 *ptr = base[2 + h]; | |
106 base[2 + h] = sym_index; | |
107 base[1]++; | |
108 /* we resize the hash table */ | |
109 hs->nb_hashed_syms++; | |
110 if (hs->nb_hashed_syms > 2 * nbuckets) { | |
111 rebuild_hash(s, 2 * nbuckets); | |
112 } | |
113 } else { | |
114 *ptr = 0; | |
115 base[1]++; | |
116 } | |
117 } | |
118 return sym_index; | |
119 } | |
120 | |
121 /* find global ELF symbol 'name' and return its index. Return 0 if not | |
122 found. */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
123 static int find_elf_sym(Section *s, char *name) |
140 | 124 { |
125 Elf32_Sym *sym; | |
126 Section *hs; | |
127 int nbuckets, sym_index, h; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
128 char *name1; |
140 | 129 |
130 hs = s->hash; | |
131 if (!hs) | |
132 return 0; | |
133 nbuckets = ((int *)hs->data)[0]; | |
134 h = elf_hash(name) % nbuckets; | |
135 sym_index = ((int *)hs->data)[2 + h]; | |
136 while (sym_index != 0) { | |
137 sym = &((Elf32_Sym *)s->data)[sym_index]; | |
138 name1 = s->link->data + sym->st_name; | |
139 if (!strcmp(name, name1)) | |
140 return sym_index; | |
141 sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; | |
142 } | |
143 return 0; | |
144 } | |
145 | |
146 /* return elf symbol value or error */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
147 int tcc_get_symbol(TCCState *s, unsigned long *pval, char *name) |
140 | 148 { |
149 int sym_index; | |
150 Elf32_Sym *sym; | |
151 | |
152 sym_index = find_elf_sym(symtab_section, name); | |
153 if (!sym_index) | |
283 | 154 return -1; |
140 | 155 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
283 | 156 *pval = sym->st_value; |
157 return 0; | |
158 } | |
159 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
160 void *tcc_get_symbol_err(TCCState *s, char *name) |
283 | 161 { |
162 unsigned long val; | |
163 if (tcc_get_symbol(s, &val, name) < 0) | |
164 error("%s not defined", name); | |
165 return (void *)val; | |
140 | 166 } |
167 | |
168 /* add an elf symbol : check if it is already defined and patch | |
169 it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ | |
170 static int add_elf_sym(Section *s, unsigned long value, unsigned long size, | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
171 int info, int other, int sh_num, char *name) |
140 | 172 { |
173 Elf32_Sym *esym; | |
174 int sym_bind, sym_index, sym_type, esym_bind; | |
469
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
175 unsigned char sym_vis, esym_vis, new_vis; |
140 | 176 |
177 sym_bind = ELF32_ST_BIND(info); | |
178 sym_type = ELF32_ST_TYPE(info); | |
469
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
179 sym_vis = ELF32_ST_VISIBILITY(other); |
140 | 180 |
181 if (sym_bind != STB_LOCAL) { | |
182 /* we search global or weak symbols */ | |
183 sym_index = find_elf_sym(s, name); | |
184 if (!sym_index) | |
185 goto do_def; | |
186 esym = &((Elf32_Sym *)s->data)[sym_index]; | |
187 if (esym->st_shndx != SHN_UNDEF) { | |
188 esym_bind = ELF32_ST_BIND(esym->st_info); | |
469
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
189 /* propagate the most constraining visibility */ |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
190 /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */ |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
191 esym_vis = ELF32_ST_VISIBILITY(esym->st_other); |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
192 if (esym_vis == STV_DEFAULT) { |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
193 new_vis = sym_vis; |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
194 } else if (sym_vis == STV_DEFAULT) { |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
195 new_vis = esym_vis; |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
196 } else { |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
197 new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
198 } |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
199 esym->st_other = (esym->st_other & ~ELF32_ST_VISIBILITY(UCHAR_MAX)) |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
200 | new_vis; |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
201 other = esym->st_other; /* in case we have to patch esym */ |
140 | 202 if (sh_num == SHN_UNDEF) { |
203 /* ignore adding of undefined symbol if the | |
204 corresponding symbol is already defined */ | |
205 } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { | |
206 /* global overrides weak, so patch */ | |
207 goto do_patch; | |
208 } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { | |
209 /* weak is ignored if already global */ | |
469
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
210 } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { |
bb13836ab658
Patch from Vincent Pit to fix visibility problems in the linker (resulting
Rob Landley <rob@landley.net>
parents:
409
diff
changeset
|
211 /* ignore hidden symbols after */ |
140 | 212 } else { |
213 #if 0 | |
214 printf("new_bind=%d new_shndx=%d last_bind=%d old_shndx=%d\n", | |
215 sym_bind, sh_num, esym_bind, esym->st_shndx); | |
216 #endif | |
217 /* NOTE: we accept that two DLL define the same symbol */ | |
174 | 218 if (s != tcc_state->dynsymtab_section) |
219 error_noabort("'%s' defined twice", name); | |
140 | 220 } |
221 } else { | |
222 do_patch: | |
223 esym->st_info = ELF32_ST_INFO(sym_bind, sym_type); | |
224 esym->st_shndx = sh_num; | |
225 esym->st_value = value; | |
226 esym->st_size = size; | |
356 | 227 esym->st_other = other; |
140 | 228 } |
229 } else { | |
230 do_def: | |
231 sym_index = put_elf_sym(s, value, size, | |
356 | 232 ELF32_ST_INFO(sym_bind, sym_type), other, |
140 | 233 sh_num, name); |
234 } | |
235 return sym_index; | |
236 } | |
237 | |
238 /* put relocation */ | |
239 static void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, | |
240 int type, int symbol) | |
241 { | |
242 char buf[256]; | |
243 Section *sr; | |
244 Elf32_Rel *rel; | |
245 | |
246 sr = s->reloc; | |
247 if (!sr) { | |
248 /* if no relocation section, create it */ | |
249 snprintf(buf, sizeof(buf), ".rel%s", s->name); | |
250 /* if the symtab is allocated, then we consider the relocation | |
251 are also */ | |
174 | 252 sr = new_section(tcc_state, buf, SHT_REL, symtab->sh_flags); |
140 | 253 sr->sh_entsize = sizeof(Elf32_Rel); |
254 sr->link = symtab; | |
255 sr->sh_info = s->sh_num; | |
256 s->reloc = sr; | |
257 } | |
258 rel = section_ptr_add(sr, sizeof(Elf32_Rel)); | |
259 rel->r_offset = offset; | |
260 rel->r_info = ELF32_R_INFO(symbol, type); | |
261 } | |
262 | |
263 /* put stab debug information */ | |
264 | |
265 typedef struct { | |
266 unsigned long n_strx; /* index into string table of name */ | |
267 unsigned char n_type; /* type of symbol */ | |
268 unsigned char n_other; /* misc info (usually empty) */ | |
269 unsigned short n_desc; /* description field */ | |
270 unsigned long n_value; /* value of symbol */ | |
271 } Stab_Sym; | |
272 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
273 static void put_stabs(char *str, int type, int other, int desc, |
140 | 274 unsigned long value) |
275 { | |
276 Stab_Sym *sym; | |
277 | |
278 sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); | |
279 if (str) { | |
280 sym->n_strx = put_elf_str(stabstr_section, str); | |
281 } else { | |
282 sym->n_strx = 0; | |
283 } | |
284 sym->n_type = type; | |
285 sym->n_other = other; | |
286 sym->n_desc = desc; | |
287 sym->n_value = value; | |
288 } | |
289 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
290 static void put_stabs_r(char *str, int type, int other, int desc, |
140 | 291 unsigned long value, Section *sec, int sym_index) |
292 { | |
293 put_stabs(str, type, other, desc, value); | |
294 put_elf_reloc(symtab_section, stab_section, | |
295 stab_section->data_offset - sizeof(unsigned long), | |
296 R_DATA_32, sym_index); | |
297 } | |
298 | |
299 static void put_stabn(int type, int other, int desc, int value) | |
300 { | |
301 put_stabs(NULL, type, other, desc, value); | |
302 } | |
303 | |
304 static void put_stabd(int type, int other, int desc) | |
305 { | |
306 put_stabs(NULL, type, other, desc, 0); | |
307 } | |
308 | |
309 /* In an ELF file symbol table, the local symbols must appear below | |
310 the global and weak ones. Since TCC cannot sort it while generating | |
311 the code, we must do it after. All the relocation tables are also | |
312 modified to take into account the symbol table sorting */ | |
174 | 313 static void sort_syms(TCCState *s1, Section *s) |
140 | 314 { |
315 int *old_to_new_syms; | |
316 Elf32_Sym *new_syms; | |
317 int nb_syms, i; | |
318 Elf32_Sym *p, *q; | |
319 Elf32_Rel *rel, *rel_end; | |
320 Section *sr; | |
321 int type, sym_index; | |
322 | |
323 nb_syms = s->data_offset / sizeof(Elf32_Sym); | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
324 new_syms = xmalloc(nb_syms * sizeof(Elf32_Sym)); |
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
325 old_to_new_syms = xmalloc(nb_syms * sizeof(int)); |
140 | 326 |
327 /* first pass for local symbols */ | |
328 p = (Elf32_Sym *)s->data; | |
329 q = new_syms; | |
330 for(i = 0; i < nb_syms; i++) { | |
331 if (ELF32_ST_BIND(p->st_info) == STB_LOCAL) { | |
332 old_to_new_syms[i] = q - new_syms; | |
333 *q++ = *p; | |
334 } | |
335 p++; | |
336 } | |
337 /* save the number of local symbols in section header */ | |
338 s->sh_info = q - new_syms; | |
339 | |
340 /* then second pass for non local symbols */ | |
341 p = (Elf32_Sym *)s->data; | |
342 for(i = 0; i < nb_syms; i++) { | |
343 if (ELF32_ST_BIND(p->st_info) != STB_LOCAL) { | |
344 old_to_new_syms[i] = q - new_syms; | |
345 *q++ = *p; | |
346 } | |
347 p++; | |
348 } | |
349 | |
350 /* we copy the new symbols to the old */ | |
351 memcpy(s->data, new_syms, nb_syms * sizeof(Elf32_Sym)); | |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
352 free(new_syms); |
140 | 353 |
354 /* now we modify all the relocations */ | |
174 | 355 for(i = 1; i < s1->nb_sections; i++) { |
356 sr = s1->sections[i]; | |
140 | 357 if (sr->sh_type == SHT_REL && sr->link == s) { |
358 rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); | |
359 for(rel = (Elf32_Rel *)sr->data; | |
360 rel < rel_end; | |
361 rel++) { | |
362 sym_index = ELF32_R_SYM(rel->r_info); | |
363 type = ELF32_R_TYPE(rel->r_info); | |
364 sym_index = old_to_new_syms[sym_index]; | |
365 rel->r_info = ELF32_R_INFO(sym_index, type); | |
366 } | |
367 } | |
368 } | |
369 | |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
370 free(old_to_new_syms); |
140 | 371 } |
372 | |
373 /* relocate common symbols in the .bss section */ | |
374 static void relocate_common_syms(void) | |
375 { | |
376 Elf32_Sym *sym, *sym_end; | |
377 unsigned long offset, align; | |
378 | |
379 sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); | |
380 for(sym = (Elf32_Sym *)symtab_section->data + 1; | |
381 sym < sym_end; | |
382 sym++) { | |
383 if (sym->st_shndx == SHN_COMMON) { | |
384 /* align symbol */ | |
385 align = sym->st_value; | |
386 offset = bss_section->data_offset; | |
387 offset = (offset + align - 1) & -align; | |
388 sym->st_value = offset; | |
389 sym->st_shndx = bss_section->sh_num; | |
390 offset += sym->st_size; | |
391 bss_section->data_offset = offset; | |
392 } | |
393 } | |
394 } | |
395 | |
396 /* relocate symbol table, resolve undefined symbols if do_resolve is | |
397 true and output error if undefined symbol. */ | |
174 | 398 static void relocate_syms(TCCState *s1, int do_resolve) |
140 | 399 { |
400 Elf32_Sym *sym, *esym, *sym_end; | |
401 int sym_bind, sh_num, sym_index; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
402 char *name; |
140 | 403 unsigned long addr; |
404 | |
405 sym_end = (Elf32_Sym *)(symtab_section->data + symtab_section->data_offset); | |
406 for(sym = (Elf32_Sym *)symtab_section->data + 1; | |
407 sym < sym_end; | |
408 sym++) { | |
409 sh_num = sym->st_shndx; | |
410 if (sh_num == SHN_UNDEF) { | |
411 name = strtab_section->data + sym->st_name; | |
412 if (do_resolve) { | |
413 name = symtab_section->link->data + sym->st_name; | |
350 | 414 addr = (unsigned long)resolve_sym(s1, name, ELF32_ST_TYPE(sym->st_info)); |
140 | 415 if (addr) { |
416 sym->st_value = addr; | |
417 goto found; | |
418 } | |
174 | 419 } else if (s1->dynsym) { |
140 | 420 /* if dynamic symbol exist, then use it */ |
174 | 421 sym_index = find_elf_sym(s1->dynsym, name); |
140 | 422 if (sym_index) { |
174 | 423 esym = &((Elf32_Sym *)s1->dynsym->data)[sym_index]; |
140 | 424 sym->st_value = esym->st_value; |
425 goto found; | |
426 } | |
427 } | |
428 /* XXX: _fp_hw seems to be part of the ABI, so we ignore | |
429 it */ | |
430 if (!strcmp(name, "_fp_hw")) | |
431 goto found; | |
432 /* only weak symbols are accepted to be undefined. Their | |
433 value is zero */ | |
434 sym_bind = ELF32_ST_BIND(sym->st_info); | |
435 if (sym_bind == STB_WEAK) { | |
436 sym->st_value = 0; | |
437 } else { | |
174 | 438 error_noabort("undefined symbol '%s'", name); |
140 | 439 } |
440 } else if (sh_num < SHN_LORESERVE) { | |
441 /* add section base */ | |
174 | 442 sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
140 | 443 } |
444 found: ; | |
445 } | |
446 } | |
447 | |
228 | 448 /* relocate a given section (CPU dependent) */ |
140 | 449 static void relocate_section(TCCState *s1, Section *s) |
450 { | |
451 Section *sr; | |
452 Elf32_Rel *rel, *rel_end, *qrel; | |
453 Elf32_Sym *sym; | |
342 | 454 int type, sym_index; |
140 | 455 unsigned char *ptr; |
456 unsigned long val, addr; | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
457 #if defined(TINYCC_TARGET_I386) |
342 | 458 int esym_index; |
459 #endif | |
140 | 460 |
461 sr = s->reloc; | |
462 rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); | |
463 qrel = (Elf32_Rel *)sr->data; | |
464 for(rel = qrel; | |
465 rel < rel_end; | |
466 rel++) { | |
467 ptr = s->data + rel->r_offset; | |
468 | |
469 sym_index = ELF32_R_SYM(rel->r_info); | |
470 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
471 val = sym->st_value; | |
472 type = ELF32_R_TYPE(rel->r_info); | |
473 addr = s->sh_addr + rel->r_offset; | |
474 | |
475 /* CPU specific */ | |
476 switch(type) { | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
477 #if defined(TINYCC_TARGET_I386) |
140 | 478 case R_386_32: |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
479 if (tccg_output_type == TCC_OUTPUT_DLL) { |
174 | 480 esym_index = s1->symtab_to_dynsym[sym_index]; |
140 | 481 qrel->r_offset = rel->r_offset; |
482 if (esym_index) { | |
483 qrel->r_info = ELF32_R_INFO(esym_index, R_386_32); | |
484 qrel++; | |
485 break; | |
486 } else { | |
487 qrel->r_info = ELF32_R_INFO(0, R_386_RELATIVE); | |
488 qrel++; | |
489 } | |
490 } | |
491 *(int *)ptr += val; | |
492 break; | |
493 case R_386_PC32: | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
494 if (tccg_output_type == TCC_OUTPUT_DLL) { |
140 | 495 /* DLL relocation */ |
174 | 496 esym_index = s1->symtab_to_dynsym[sym_index]; |
140 | 497 if (esym_index) { |
498 qrel->r_offset = rel->r_offset; | |
499 qrel->r_info = ELF32_R_INFO(esym_index, R_386_PC32); | |
500 qrel++; | |
501 break; | |
502 } | |
503 } | |
504 *(int *)ptr += val - addr; | |
505 break; | |
506 case R_386_PLT32: | |
507 *(int *)ptr += val - addr; | |
508 break; | |
509 case R_386_GLOB_DAT: | |
510 case R_386_JMP_SLOT: | |
511 *(int *)ptr = val; | |
512 break; | |
513 case R_386_GOTPC: | |
174 | 514 *(int *)ptr += s1->got->sh_addr - addr; |
140 | 515 break; |
516 case R_386_GOTOFF: | |
174 | 517 *(int *)ptr += val - s1->got->sh_addr; |
140 | 518 break; |
519 case R_386_GOT32: | |
520 /* we load the got offset */ | |
174 | 521 *(int *)ptr += s1->got_offsets[sym_index]; |
140 | 522 break; |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
523 #elif defined(TINYCC_TARGET_ARM) |
295 | 524 case R_ARM_PC24: |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
525 case R_ARM_CALL: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
526 case R_ARM_JUMP24: |
295 | 527 case R_ARM_PLT32: |
528 { | |
529 int x; | |
530 x = (*(int *)ptr)&0xffffff; | |
531 (*(int *)ptr) &= 0xff000000; | |
532 if (x & 0x800000) | |
533 x -= 0x1000000; | |
534 x *= 4; | |
535 x += val - addr; | |
536 if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) | |
537 error("can't relocate value at %x",addr); | |
538 x >>= 2; | |
539 x &= 0xffffff; | |
540 (*(int *)ptr) |= x; | |
541 } | |
542 break; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
543 case R_ARM_PREL31: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
544 { |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
545 int x; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
546 x = (*(int *)ptr) & 0x7fffffff; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
547 (*(int *)ptr) &= 0x80000000; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
548 x = (x * 2) / 2; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
549 x += val - addr; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
550 if((x^(x>>1))&0x40000000) |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
551 error("can't relocate value at %x",addr); |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
552 (*(int *)ptr) |= x & 0x7fffffff; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
553 } |
295 | 554 case R_ARM_ABS32: |
555 *(int *)ptr += val; | |
556 break; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
557 case R_ARM_BASE_PREL: |
295 | 558 *(int *)ptr += s1->got->sh_addr - addr; |
559 break; | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
560 case R_ARM_GOTOFF32: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
561 *(int *)ptr += val - s1->got->sh_addr; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
562 break; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
563 case R_ARM_GOT_BREL: |
295 | 564 /* we load the got offset */ |
565 *(int *)ptr += s1->got_offsets[sym_index]; | |
566 break; | |
567 case R_ARM_COPY: | |
568 break; | |
569 default: | |
570 fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", | |
571 type,addr,(unsigned int )ptr,val); | |
572 break; | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
573 #elif defined(TINYCC_TARGET_C67) |
305 | 574 case R_C60_32: |
575 *(int *)ptr += val; | |
576 break; | |
309 | 577 case R_C60LO16: |
578 { | |
579 uint32_t orig; | |
580 | |
581 /* put the low 16 bits of the absolute address */ | |
582 // add to what is already there | |
583 | |
584 orig = ((*(int *)(ptr )) >> 7) & 0xffff; | |
585 orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; | |
586 | |
587 //patch both at once - assumes always in pairs Low - High | |
588 | |
589 *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); | |
590 *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); | |
591 } | |
592 break; | |
593 case R_C60HI16: | |
594 break; | |
305 | 595 default: |
596 fprintf(stderr,"FIXME: handle reloc type %x at %lx [%.8x] to %lx\n", | |
597 type,addr,(unsigned int )ptr,val); | |
598 break; | |
295 | 599 #else |
600 #error unsupported processor | |
601 #endif | |
140 | 602 } |
603 } | |
604 /* if the relocation is allocated, we change its symbol table */ | |
605 if (sr->sh_flags & SHF_ALLOC) | |
174 | 606 sr->link = s1->dynsym; |
140 | 607 } |
608 | |
609 /* relocate relocation table in 'sr' */ | |
174 | 610 static void relocate_rel(TCCState *s1, Section *sr) |
140 | 611 { |
612 Section *s; | |
613 Elf32_Rel *rel, *rel_end; | |
614 | |
174 | 615 s = s1->sections[sr->sh_info]; |
140 | 616 rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); |
617 for(rel = (Elf32_Rel *)sr->data; | |
618 rel < rel_end; | |
619 rel++) { | |
620 rel->r_offset += s->sh_addr; | |
621 } | |
622 } | |
623 | |
624 /* count the number of dynamic relocations so that we can reserve | |
625 their space */ | |
174 | 626 static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
140 | 627 { |
628 Elf32_Rel *rel, *rel_end; | |
629 int sym_index, esym_index, type, count; | |
630 | |
631 count = 0; | |
632 rel_end = (Elf32_Rel *)(sr->data + sr->data_offset); | |
633 for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++) { | |
634 sym_index = ELF32_R_SYM(rel->r_info); | |
635 type = ELF32_R_TYPE(rel->r_info); | |
636 switch(type) { | |
637 case R_386_32: | |
638 count++; | |
639 break; | |
640 case R_386_PC32: | |
174 | 641 esym_index = s1->symtab_to_dynsym[sym_index]; |
140 | 642 if (esym_index) |
643 count++; | |
644 break; | |
645 default: | |
646 break; | |
647 } | |
648 } | |
649 if (count) { | |
650 /* allocate the section */ | |
651 sr->sh_flags |= SHF_ALLOC; | |
652 sr->sh_size = count * sizeof(Elf32_Rel); | |
653 } | |
654 return count; | |
655 } | |
656 | |
174 | 657 static void put_got_offset(TCCState *s1, int index, unsigned long val) |
140 | 658 { |
659 int n; | |
660 unsigned long *tab; | |
661 | |
174 | 662 if (index >= s1->nb_got_offsets) { |
140 | 663 /* find immediately bigger power of 2 and reallocate array */ |
664 n = 1; | |
665 while (index >= n) | |
666 n *= 2; | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
667 tab = xrealloc(s1->got_offsets, n * sizeof(unsigned long)); |
174 | 668 s1->got_offsets = tab; |
669 memset(s1->got_offsets + s1->nb_got_offsets, 0, | |
670 (n - s1->nb_got_offsets) * sizeof(unsigned long)); | |
671 s1->nb_got_offsets = n; | |
140 | 672 } |
174 | 673 s1->got_offsets[index] = val; |
140 | 674 } |
675 | |
676 /* XXX: suppress that */ | |
228 | 677 static void put32(unsigned char *p, uint32_t val) |
140 | 678 { |
679 p[0] = val; | |
680 p[1] = val >> 8; | |
681 p[2] = val >> 16; | |
682 p[3] = val >> 24; | |
683 } | |
684 | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
685 #if defined(TINYCC_TARGET_I386) || defined(TINYCC_TARGET_ARM) |
228 | 686 static uint32_t get32(unsigned char *p) |
687 { | |
688 return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); | |
689 } | |
342 | 690 #endif |
228 | 691 |
174 | 692 static void build_got(TCCState *s1) |
140 | 693 { |
694 unsigned char *ptr; | |
695 | |
696 /* if no got, then create it */ | |
174 | 697 s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
698 s1->got->sh_entsize = 4; | |
140 | 699 add_elf_sym(symtab_section, 0, 4, ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), |
356 | 700 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); |
174 | 701 ptr = section_ptr_add(s1->got, 3 * sizeof(int)); |
140 | 702 /* keep space for _DYNAMIC pointer, if present */ |
703 put32(ptr, 0); | |
704 /* two dummy got entries */ | |
705 put32(ptr + 4, 0); | |
706 put32(ptr + 8, 0); | |
707 } | |
708 | |
709 /* put a got entry corresponding to a symbol in symtab_section. 'size' | |
710 and 'info' can be modifed if more precise info comes from the DLL */ | |
174 | 711 static void put_got_entry(TCCState *s1, |
712 int reloc_type, unsigned long size, int info, | |
140 | 713 int sym_index) |
714 { | |
715 int index; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
716 char *name; |
140 | 717 Elf32_Sym *sym; |
718 unsigned long offset; | |
719 int *ptr; | |
720 | |
174 | 721 if (!s1->got) |
722 build_got(s1); | |
140 | 723 |
724 /* if a got entry already exists for that symbol, no need to add one */ | |
174 | 725 if (sym_index < s1->nb_got_offsets && |
726 s1->got_offsets[sym_index] != 0) | |
140 | 727 return; |
728 | |
174 | 729 put_got_offset(s1, sym_index, s1->got->data_offset); |
140 | 730 |
174 | 731 if (s1->dynsym) { |
140 | 732 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
733 name = symtab_section->link->data + sym->st_name; | |
734 offset = sym->st_value; | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
735 #ifdef TINYCC_TARGET_I386 |
140 | 736 if (reloc_type == R_386_JMP_SLOT) { |
228 | 737 Section *plt; |
738 uint8_t *p; | |
739 int modrm; | |
740 | |
741 /* if we build a DLL, we add a %ebx offset */ | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
742 if (tccg_output_type == TCC_OUTPUT_DLL) |
228 | 743 modrm = 0xa3; |
744 else | |
745 modrm = 0x25; | |
746 | |
747 /* add a PLT entry */ | |
748 plt = s1->plt; | |
749 if (plt->data_offset == 0) { | |
750 /* first plt entry */ | |
751 p = section_ptr_add(plt, 16); | |
752 p[0] = 0xff; /* pushl got + 4 */ | |
753 p[1] = modrm + 0x10; | |
754 put32(p + 2, 4); | |
755 p[6] = 0xff; /* jmp *(got + 8) */ | |
756 p[7] = modrm; | |
757 put32(p + 8, 8); | |
758 } | |
759 | |
760 p = section_ptr_add(plt, 16); | |
761 p[0] = 0xff; /* jmp *(got + x) */ | |
762 p[1] = modrm; | |
763 put32(p + 2, s1->got->data_offset); | |
764 p[6] = 0x68; /* push $xxx */ | |
765 put32(p + 7, (plt->data_offset - 32) >> 1); | |
766 p[11] = 0xe9; /* jmp plt_start */ | |
767 put32(p + 12, -(plt->data_offset)); | |
768 | |
769 /* the symbol is modified so that it will be relocated to | |
770 the PLT */ | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
771 if (tccg_output_type == TCC_OUTPUT_EXE) |
228 | 772 offset = plt->data_offset - 16; |
140 | 773 } |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
774 #elif defined(TINYCC_TARGET_ARM) |
295 | 775 if (reloc_type == R_ARM_JUMP_SLOT) { |
776 Section *plt; | |
777 uint8_t *p; | |
778 | |
779 /* if we build a DLL, we add a %ebx offset */ | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
780 if (tccg_output_type == TCC_OUTPUT_DLL) |
295 | 781 error("DLLs unimplemented!"); |
782 | |
783 /* add a PLT entry */ | |
784 plt = s1->plt; | |
785 if (plt->data_offset == 0) { | |
786 /* first plt entry */ | |
787 p = section_ptr_add(plt, 16); | |
788 put32(p , 0xe52de004); | |
789 put32(p + 4, 0xe59fe010); | |
790 put32(p + 8, 0xe08fe00e); | |
791 put32(p + 12, 0xe5bef008); | |
792 } | |
793 | |
794 p = section_ptr_add(plt, 16); | |
795 put32(p , 0xe59fc004); | |
796 put32(p+4, 0xe08fc00c); | |
797 put32(p+8, 0xe59cf000); | |
798 put32(p+12, s1->got->data_offset); | |
799 | |
800 /* the symbol is modified so that it will be relocated to | |
801 the PLT */ | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
802 if (tccg_output_type == TCC_OUTPUT_EXE) |
295 | 803 offset = plt->data_offset - 16; |
804 } | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
805 #elif defined(TINYCC_TARGET_C67) |
305 | 806 error("C67 got not implemented"); |
295 | 807 #else |
808 #error unsupported CPU | |
809 #endif | |
174 | 810 index = put_elf_sym(s1->dynsym, offset, |
140 | 811 size, info, 0, sym->st_shndx, name); |
812 /* put a got entry */ | |
174 | 813 put_elf_reloc(s1->dynsym, s1->got, |
814 s1->got->data_offset, | |
140 | 815 reloc_type, index); |
816 } | |
174 | 817 ptr = section_ptr_add(s1->got, sizeof(int)); |
140 | 818 *ptr = 0; |
819 } | |
820 | |
821 /* build GOT and PLT entries */ | |
174 | 822 static void build_got_entries(TCCState *s1) |
140 | 823 { |
824 Section *s, *symtab; | |
825 Elf32_Rel *rel, *rel_end; | |
826 Elf32_Sym *sym; | |
827 int i, type, reloc_type, sym_index; | |
828 | |
174 | 829 for(i = 1; i < s1->nb_sections; i++) { |
830 s = s1->sections[i]; | |
140 | 831 if (s->sh_type != SHT_REL) |
832 continue; | |
833 /* no need to handle got relocations */ | |
834 if (s->link != symtab_section) | |
835 continue; | |
836 symtab = s->link; | |
837 rel_end = (Elf32_Rel *)(s->data + s->data_offset); | |
838 for(rel = (Elf32_Rel *)s->data; | |
839 rel < rel_end; | |
840 rel++) { | |
841 type = ELF32_R_TYPE(rel->r_info); | |
842 switch(type) { | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
843 #if defined(TINYCC_TARGET_I386) |
140 | 844 case R_386_GOT32: |
845 case R_386_GOTOFF: | |
846 case R_386_GOTPC: | |
847 case R_386_PLT32: | |
174 | 848 if (!s1->got) |
849 build_got(s1); | |
140 | 850 if (type == R_386_GOT32 || type == R_386_PLT32) { |
851 sym_index = ELF32_R_SYM(rel->r_info); | |
852 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
853 /* look at the symbol got offset. If none, then add one */ | |
854 if (type == R_386_GOT32) | |
855 reloc_type = R_386_GLOB_DAT; | |
856 else | |
857 reloc_type = R_386_JMP_SLOT; | |
174 | 858 put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
140 | 859 sym_index); |
860 } | |
861 break; | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
862 #elif defined(TINYCC_TARGET_ARM) |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
863 case R_ARM_GOT_BREL: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
864 case R_ARM_GOTOFF32: |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
865 case R_ARM_BASE_PREL: |
295 | 866 case R_ARM_PLT32: |
867 if (!s1->got) | |
868 build_got(s1); | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
869 if (type == R_ARM_GOT_BREL || type == R_ARM_PLT32) { |
295 | 870 sym_index = ELF32_R_SYM(rel->r_info); |
871 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
872 /* look at the symbol got offset. If none, then add one */ | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
873 if (type == R_ARM_GOT_BREL) |
295 | 874 reloc_type = R_ARM_GLOB_DAT; |
875 else | |
876 reloc_type = R_ARM_JUMP_SLOT; | |
877 put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | |
878 sym_index); | |
879 } | |
880 break; | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
881 #elif defined(TINYCC_TARGET_C67) |
305 | 882 case R_C60_GOT32: |
883 case R_C60_GOTOFF: | |
884 case R_C60_GOTPC: | |
885 case R_C60_PLT32: | |
886 if (!s1->got) | |
887 build_got(s1); | |
888 if (type == R_C60_GOT32 || type == R_C60_PLT32) { | |
889 sym_index = ELF32_R_SYM(rel->r_info); | |
890 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
891 /* look at the symbol got offset. If none, then add one */ | |
892 if (type == R_C60_GOT32) | |
893 reloc_type = R_C60_GLOB_DAT; | |
894 else | |
895 reloc_type = R_C60_JMP_SLOT; | |
896 put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | |
897 sym_index); | |
898 } | |
899 break; | |
295 | 900 #else |
901 #error unsupported CPU | |
902 #endif | |
140 | 903 default: |
904 break; | |
905 } | |
906 } | |
907 } | |
908 } | |
909 | |
174 | 910 static Section *new_symtab(TCCState *s1, |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
911 char *symtab_name, int sh_type, int sh_flags, |
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
912 char *strtab_name, |
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
913 char *hash_name, int hash_sh_flags) |
140 | 914 { |
915 Section *symtab, *strtab, *hash; | |
916 int *ptr, nb_buckets; | |
917 | |
174 | 918 symtab = new_section(s1, symtab_name, sh_type, sh_flags); |
140 | 919 symtab->sh_entsize = sizeof(Elf32_Sym); |
174 | 920 strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); |
140 | 921 put_elf_str(strtab, ""); |
922 symtab->link = strtab; | |
923 put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); | |
924 | |
925 nb_buckets = 1; | |
926 | |
174 | 927 hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); |
140 | 928 hash->sh_entsize = sizeof(int); |
929 symtab->hash = hash; | |
930 hash->link = symtab; | |
931 | |
932 ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); | |
933 ptr[0] = nb_buckets; | |
934 ptr[1] = 1; | |
935 memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); | |
936 return symtab; | |
937 } | |
938 | |
939 /* put dynamic tag */ | |
940 static void put_dt(Section *dynamic, int dt, unsigned long val) | |
941 { | |
942 Elf32_Dyn *dyn; | |
943 dyn = section_ptr_add(dynamic, sizeof(Elf32_Dyn)); | |
944 dyn->d_tag = dt; | |
945 dyn->d_un.d_val = val; | |
946 } | |
947 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
948 static void add_init_array_defines(TCCState *s1, char *section_name) |
278 | 949 { |
950 Section *s; | |
951 long end_offset; | |
952 char sym_start[1024]; | |
953 char sym_end[1024]; | |
954 | |
955 snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1); | |
956 snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1); | |
957 | |
958 s = find_section(s1, section_name); | |
959 if (!s) { | |
960 end_offset = 0; | |
961 s = data_section; | |
962 } else { | |
963 end_offset = s->data_offset; | |
964 } | |
965 | |
966 add_elf_sym(symtab_section, | |
967 0, 0, | |
356 | 968 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
278 | 969 s->sh_num, sym_start); |
970 add_elf_sym(symtab_section, | |
971 end_offset, 0, | |
356 | 972 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
278 | 973 s->sh_num, sym_end); |
974 } | |
975 | |
140 | 976 /* add tcc runtime libraries */ |
977 static void tcc_add_runtime(TCCState *s1) | |
978 { | |
979 char buf[1024]; | |
980 | |
981 #ifdef CONFIG_TCC_BCHECK | |
982 if (do_bounds_check) { | |
983 unsigned long *ptr; | |
984 Section *init_section; | |
985 unsigned char *pinit; | |
986 int sym_index; | |
987 | |
988 /* XXX: add an object file to do that */ | |
989 ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); | |
990 *ptr = 0; | |
991 add_elf_sym(symtab_section, 0, 0, | |
356 | 992 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 993 bounds_section->sh_num, "__bounds_start"); |
994 /* add bound check code */ | |
522
a6abef04cb53
Fix path logic so "hello world" builds again. (Still need to finish install.)
Rob Landley <rob@landley.net>
parents:
519
diff
changeset
|
995 snprintf(buf, sizeof(buf), "%s/bcheck.o", tinycc_path); |
140 | 996 tcc_add_file(s1, buf); |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
997 #ifdef TINYCC_TARGET_I386 |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
998 if (tccg_output_type != TCC_OUTPUT_MEMORY) { |
140 | 999 /* add 'call __bound_init()' in .init section */ |
174 | 1000 init_section = find_section(s1, ".init"); |
140 | 1001 pinit = section_ptr_add(init_section, 5); |
1002 pinit[0] = 0xe8; | |
1003 put32(pinit + 1, -4); | |
1004 sym_index = find_elf_sym(symtab_section, "__bound_init"); | |
1005 put_elf_reloc(symtab_section, init_section, | |
1006 init_section->data_offset - 4, R_386_PC32, sym_index); | |
1007 } | |
1008 #endif | |
1009 } | |
1010 #endif | |
511
374af493d0ac
More work on the library paths so we can override enough things to build
Rob Landley <rob@landley.net>
parents:
507
diff
changeset
|
1011 // add libc |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1012 if (!tccg_nostdlib) { |
289 | 1013 tcc_add_library(s1, "c"); |
547
9778e985b450
Rename runtime library to libtinyccrt-$ARCH.a, build libtinycc-$ARCH.so to
Rob Landley <rob@landley.net>
parents:
529
diff
changeset
|
1014 tcc_add_library(s1, "tinyccrt-" TINYCC_TARGET); |
511
374af493d0ac
More work on the library paths so we can override enough things to build
Rob Landley <rob@landley.net>
parents:
507
diff
changeset
|
1015 // add crt end if not memory output |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1016 if (tccg_output_type != TCC_OUTPUT_MEMORY) |
564
d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
Rob Landley <rob@landley.net>
parents:
555
diff
changeset
|
1017 tcc_add_dll(s1, "crtn.o", AFF_PRINT_ERROR); |
140 | 1018 } |
325 | 1019 } |
1020 | |
1021 /* add various standard linker symbols (must be done after the | |
1022 sections are filled (for example after allocating common | |
1023 symbols)) */ | |
1024 static void tcc_add_linker_symbols(TCCState *s1) | |
1025 { | |
1026 char buf[1024]; | |
1027 int i; | |
1028 Section *s; | |
1029 | |
140 | 1030 add_elf_sym(symtab_section, |
1031 text_section->data_offset, 0, | |
356 | 1032 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 1033 text_section->sh_num, "_etext"); |
1034 add_elf_sym(symtab_section, | |
1035 data_section->data_offset, 0, | |
356 | 1036 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 1037 data_section->sh_num, "_edata"); |
1038 add_elf_sym(symtab_section, | |
1039 bss_section->data_offset, 0, | |
356 | 1040 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 1041 bss_section->sh_num, "_end"); |
278 | 1042 /* horrible new standard ldscript defines */ |
1043 add_init_array_defines(s1, ".preinit_array"); | |
1044 add_init_array_defines(s1, ".init_array"); | |
1045 add_init_array_defines(s1, ".fini_array"); | |
1046 | |
140 | 1047 /* add start and stop symbols for sections whose name can be |
1048 expressed in C */ | |
174 | 1049 for(i = 1; i < s1->nb_sections; i++) { |
1050 s = s1->sections[i]; | |
140 | 1051 if (s->sh_type == SHT_PROGBITS && |
1052 (s->sh_flags & SHF_ALLOC)) { | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1053 char *p; |
140 | 1054 int ch; |
1055 | |
1056 /* check if section name can be expressed in C */ | |
1057 p = s->name; | |
1058 for(;;) { | |
1059 ch = *p; | |
1060 if (!ch) | |
1061 break; | |
505
9311fc3f8e39
Every use of isid() can be replaced by isidnum_table[], so do it.
Rob Landley <rob@landley.net>
parents:
503
diff
changeset
|
1062 if (!isidnum_table[ch]) |
140 | 1063 goto next_sec; |
1064 p++; | |
1065 } | |
1066 snprintf(buf, sizeof(buf), "__start_%s", s->name); | |
1067 add_elf_sym(symtab_section, | |
1068 0, 0, | |
356 | 1069 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 1070 s->sh_num, buf); |
1071 snprintf(buf, sizeof(buf), "__stop_%s", s->name); | |
1072 add_elf_sym(symtab_section, | |
1073 s->data_offset, 0, | |
356 | 1074 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
140 | 1075 s->sh_num, buf); |
1076 } | |
1077 next_sec: ; | |
1078 } | |
1079 } | |
1080 | |
1081 /* name of ELF interpreter */ | |
212 | 1082 #ifdef __FreeBSD__ |
1083 static char elf_interp[] = "/usr/libexec/ld-elf.so.1"; | |
1084 #else | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1085 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1086 static char elf_interp[] = "/lib/ld-linux.so.3"; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1087 #else |
140 | 1088 static char elf_interp[] = "/lib/ld-linux.so.2"; |
212 | 1089 #endif |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1090 #endif |
140 | 1091 |
325 | 1092 static void tcc_output_binary(TCCState *s1, FILE *f, |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1093 int *section_order) |
325 | 1094 { |
1095 Section *s; | |
1096 int i, offset, size; | |
1097 | |
1098 offset = 0; | |
1099 for(i=1;i<s1->nb_sections;i++) { | |
1100 s = s1->sections[section_order[i]]; | |
1101 if (s->sh_type != SHT_NOBITS && | |
1102 (s->sh_flags & SHF_ALLOC)) { | |
1103 while (offset < s->sh_offset) { | |
1104 fputc(0, f); | |
1105 offset++; | |
1106 } | |
1107 size = s->sh_size; | |
1108 fwrite(s->data, 1, size, f); | |
1109 offset += size; | |
1110 } | |
1111 } | |
1112 } | |
1113 | |
140 | 1114 /* output an ELF file */ |
1115 /* XXX: suppress unneeded sections */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1116 int tcc_output_file(TCCState *s1, char *filename) |
140 | 1117 { |
1118 Elf32_Ehdr ehdr; | |
1119 FILE *f; | |
174 | 1120 int fd, mode, ret; |
140 | 1121 int *section_order; |
1122 int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k; | |
1123 unsigned long addr; | |
1124 Section *strsec, *s; | |
1125 Elf32_Shdr shdr, *sh; | |
1126 Elf32_Phdr *phdr, *ph; | |
228 | 1127 Section *interp, *dynamic, *dynstr; |
140 | 1128 unsigned long saved_dynamic_data_offset; |
1129 Elf32_Sym *sym; | |
1130 int type, file_type; | |
1131 unsigned long rel_addr, rel_size; | |
1132 | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1133 file_type = tccg_output_type; |
174 | 1134 s1->nb_errors = 0; |
140 | 1135 |
319 | 1136 if (file_type != TCC_OUTPUT_OBJ) { |
140 | 1137 tcc_add_runtime(s1); |
319 | 1138 } |
140 | 1139 |
174 | 1140 phdr = NULL; |
1141 section_order = NULL; | |
140 | 1142 interp = NULL; |
1143 dynamic = NULL; | |
1144 dynstr = NULL; /* avoid warning */ | |
1145 saved_dynamic_data_offset = 0; /* avoid warning */ | |
174 | 1146 |
140 | 1147 if (file_type != TCC_OUTPUT_OBJ) { |
325 | 1148 relocate_common_syms(); |
1149 | |
1150 tcc_add_linker_symbols(s1); | |
140 | 1151 |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1152 if (!tccg_static_link) { |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1153 char *name; |
140 | 1154 int sym_index, index; |
1155 Elf32_Sym *esym, *sym_end; | |
1156 | |
1157 if (file_type == TCC_OUTPUT_EXE) { | |
1158 char *ptr; | |
1159 /* add interpreter section only if executable */ | |
174 | 1160 interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
140 | 1161 interp->sh_addralign = 1; |
1162 ptr = section_ptr_add(interp, sizeof(elf_interp)); | |
1163 strcpy(ptr, elf_interp); | |
1164 } | |
1165 | |
1166 /* add dynamic symbol table */ | |
174 | 1167 s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
1168 ".dynstr", | |
1169 ".hash", SHF_ALLOC); | |
1170 dynstr = s1->dynsym->link; | |
140 | 1171 |
1172 /* add dynamic section */ | |
174 | 1173 dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
140 | 1174 SHF_ALLOC | SHF_WRITE); |
1175 dynamic->link = dynstr; | |
1176 dynamic->sh_entsize = sizeof(Elf32_Dyn); | |
1177 | |
1178 /* add PLT */ | |
228 | 1179 s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
1180 SHF_ALLOC | SHF_EXECINSTR); | |
1181 s1->plt->sh_entsize = 4; | |
140 | 1182 |
174 | 1183 build_got(s1); |
140 | 1184 |
1185 /* scan for undefined symbols and see if they are in the | |
1186 dynamic symbols. If a symbol STT_FUNC is found, then we | |
1187 add it in the PLT. If a symbol STT_OBJECT is found, we | |
1188 add it in the .bss section with a suitable relocation */ | |
1189 sym_end = (Elf32_Sym *)(symtab_section->data + | |
1190 symtab_section->data_offset); | |
1191 if (file_type == TCC_OUTPUT_EXE) { | |
1192 for(sym = (Elf32_Sym *)symtab_section->data + 1; | |
1193 sym < sym_end; | |
1194 sym++) { | |
1195 if (sym->st_shndx == SHN_UNDEF) { | |
1196 name = symtab_section->link->data + sym->st_name; | |
174 | 1197 sym_index = find_elf_sym(s1->dynsymtab_section, name); |
140 | 1198 if (sym_index) { |
174 | 1199 esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index]; |
140 | 1200 type = ELF32_ST_TYPE(esym->st_info); |
1201 if (type == STT_FUNC) { | |
295 | 1202 put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
140 | 1203 esym->st_info, |
1204 sym - (Elf32_Sym *)symtab_section->data); | |
1205 } else if (type == STT_OBJECT) { | |
1206 unsigned long offset; | |
1207 offset = bss_section->data_offset; | |
1208 /* XXX: which alignment ? */ | |
272 | 1209 offset = (offset + 16 - 1) & -16; |
174 | 1210 index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
140 | 1211 esym->st_info, 0, |
1212 bss_section->sh_num, name); | |
174 | 1213 put_elf_reloc(s1->dynsym, bss_section, |
295 | 1214 offset, R_COPY, index); |
140 | 1215 offset += esym->st_size; |
1216 bss_section->data_offset = offset; | |
1217 } | |
1218 } else { | |
1219 /* STB_WEAK undefined symbols are accepted */ | |
1220 /* XXX: _fp_hw seems to be part of the ABI, so we ignore | |
1221 it */ | |
1222 if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || | |
1223 !strcmp(name, "_fp_hw")) { | |
1224 } else { | |
174 | 1225 error_noabort("undefined symbol '%s'", name); |
140 | 1226 } |
1227 } | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1228 } else if (tccg_rdynamic && |
272 | 1229 ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
1230 /* if -rdynamic option, then export all non | |
1231 local symbols */ | |
1232 name = symtab_section->link->data + sym->st_name; | |
1233 put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | |
1234 sym->st_info, 0, | |
1235 sym->st_shndx, name); | |
140 | 1236 } |
1237 } | |
1238 | |
174 | 1239 if (s1->nb_errors) |
1240 goto fail; | |
1241 | |
140 | 1242 /* now look at unresolved dynamic symbols and export |
1243 corresponding symbol */ | |
174 | 1244 sym_end = (Elf32_Sym *)(s1->dynsymtab_section->data + |
1245 s1->dynsymtab_section->data_offset); | |
1246 for(esym = (Elf32_Sym *)s1->dynsymtab_section->data + 1; | |
140 | 1247 esym < sym_end; |
1248 esym++) { | |
1249 if (esym->st_shndx == SHN_UNDEF) { | |
174 | 1250 name = s1->dynsymtab_section->link->data + esym->st_name; |
140 | 1251 sym_index = find_elf_sym(symtab_section, name); |
1252 if (sym_index) { | |
272 | 1253 /* XXX: avoid adding a symbol if already |
1254 present because of -rdynamic ? */ | |
140 | 1255 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
174 | 1256 put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
140 | 1257 sym->st_info, 0, |
1258 sym->st_shndx, name); | |
1259 } else { | |
1260 if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { | |
1261 /* weak symbols can stay undefined */ | |
1262 } else { | |
1263 warning("undefined dynamic symbol '%s'", name); | |
1264 } | |
1265 } | |
1266 } | |
1267 } | |
1268 } else { | |
1269 int nb_syms; | |
1270 /* shared library case : we simply export all the global symbols */ | |
1271 nb_syms = symtab_section->data_offset / sizeof(Elf32_Sym); | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1272 s1->symtab_to_dynsym = xzmalloc(sizeof(int) * nb_syms); |
140 | 1273 for(sym = (Elf32_Sym *)symtab_section->data + 1; |
1274 sym < sym_end; | |
1275 sym++) { | |
1276 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { | |
1277 name = symtab_section->link->data + sym->st_name; | |
174 | 1278 index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
140 | 1279 sym->st_info, 0, |
1280 sym->st_shndx, name); | |
174 | 1281 s1->symtab_to_dynsym[sym - |
1282 (Elf32_Sym *)symtab_section->data] = | |
140 | 1283 index; |
1284 } | |
1285 } | |
1286 } | |
1287 | |
174 | 1288 build_got_entries(s1); |
140 | 1289 |
1290 /* add a list of needed dlls */ | |
174 | 1291 for(i = 0; i < s1->nb_loaded_dlls; i++) { |
1292 DLLReference *dllref = s1->loaded_dlls[i]; | |
140 | 1293 if (dllref->level == 0) |
1294 put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); | |
1295 } | |
1296 /* XXX: currently, since we do not handle PIC code, we | |
1297 must relocate the readonly segments */ | |
1298 if (file_type == TCC_OUTPUT_DLL) | |
1299 put_dt(dynamic, DT_TEXTREL, 0); | |
1300 | |
1301 /* add necessary space for other entries */ | |
1302 saved_dynamic_data_offset = dynamic->data_offset; | |
1303 dynamic->data_offset += 8 * 9; | |
1304 } else { | |
1305 /* still need to build got entries in case of static link */ | |
174 | 1306 build_got_entries(s1); |
140 | 1307 } |
1308 } | |
1309 | |
1310 memset(&ehdr, 0, sizeof(ehdr)); | |
1311 | |
1312 /* we add a section for symbols */ | |
174 | 1313 strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
140 | 1314 put_elf_str(strsec, ""); |
1315 | |
1316 /* compute number of sections */ | |
174 | 1317 shnum = s1->nb_sections; |
140 | 1318 |
1319 /* this array is used to reorder sections in the output file */ | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1320 section_order = xmalloc(sizeof(int) * shnum); |
140 | 1321 section_order[0] = 0; |
1322 sh_order_index = 1; | |
1323 | |
1324 /* compute number of program headers */ | |
1325 switch(file_type) { | |
1326 default: | |
1327 case TCC_OUTPUT_OBJ: | |
1328 phnum = 0; | |
1329 break; | |
1330 case TCC_OUTPUT_EXE: | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1331 if (!tccg_static_link) |
140 | 1332 phnum = 4; |
1333 else | |
1334 phnum = 2; | |
1335 break; | |
1336 case TCC_OUTPUT_DLL: | |
1337 phnum = 3; | |
1338 break; | |
1339 } | |
1340 | |
1341 /* allocate strings for section names and decide if an unallocated | |
1342 section should be output */ | |
1343 /* NOTE: the strsec section comes last, so its size is also | |
1344 correct ! */ | |
174 | 1345 for(i = 1; i < s1->nb_sections; i++) { |
1346 s = s1->sections[i]; | |
140 | 1347 s->sh_name = put_elf_str(strsec, s->name); |
1348 /* when generating a DLL, we include relocations but we may | |
1349 patch them */ | |
1350 if (file_type == TCC_OUTPUT_DLL && | |
1351 s->sh_type == SHT_REL && | |
1352 !(s->sh_flags & SHF_ALLOC)) { | |
174 | 1353 prepare_dynamic_rel(s1, s); |
140 | 1354 } else if (do_debug || |
1355 file_type == TCC_OUTPUT_OBJ || | |
1356 (s->sh_flags & SHF_ALLOC) || | |
174 | 1357 i == (s1->nb_sections - 1)) { |
140 | 1358 /* we output all sections if debug or object file */ |
1359 s->sh_size = s->data_offset; | |
1360 } | |
1361 } | |
1362 | |
1363 /* allocate program segment headers */ | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1364 phdr = xzmalloc(phnum * sizeof(Elf32_Phdr)); |
140 | 1365 |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1366 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1367 file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); |
1368 } else { | |
1369 file_offset = 0; | |
1370 } | |
140 | 1371 if (phnum > 0) { |
1372 /* compute section to program header mapping */ | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1373 if (tccg_has_text_addr) { |
319 | 1374 int a_offset, p_offset; |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1375 addr = tccg_text_addr; |
319 | 1376 /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
1377 ELF_PAGE_SIZE */ | |
1378 a_offset = addr & (ELF_PAGE_SIZE - 1); | |
1379 p_offset = file_offset & (ELF_PAGE_SIZE - 1); | |
1380 if (a_offset < p_offset) | |
1381 a_offset += ELF_PAGE_SIZE; | |
1382 file_offset += (a_offset - p_offset); | |
1383 } else { | |
1384 if (file_type == TCC_OUTPUT_DLL) | |
1385 addr = 0; | |
1386 else | |
1387 addr = ELF_START_ADDR; | |
1388 /* compute address after headers */ | |
1389 addr += (file_offset & (ELF_PAGE_SIZE - 1)); | |
1390 } | |
1391 | |
140 | 1392 /* dynamic relocation table information, for .dynamic section */ |
1393 rel_size = 0; | |
1394 rel_addr = 0; | |
1395 | |
1396 /* leave one program header for the program interpreter */ | |
1397 ph = &phdr[0]; | |
1398 if (interp) | |
1399 ph++; | |
1400 | |
1401 for(j = 0; j < 2; j++) { | |
1402 ph->p_type = PT_LOAD; | |
1403 if (j == 0) | |
1404 ph->p_flags = PF_R | PF_X; | |
1405 else | |
1406 ph->p_flags = PF_R | PF_W; | |
1407 ph->p_align = ELF_PAGE_SIZE; | |
1408 | |
1409 /* we do the following ordering: interp, symbol tables, | |
1410 relocations, progbits, nobits */ | |
1411 /* XXX: do faster and simpler sorting */ | |
1412 for(k = 0; k < 5; k++) { | |
174 | 1413 for(i = 1; i < s1->nb_sections; i++) { |
1414 s = s1->sections[i]; | |
140 | 1415 /* compute if section should be included */ |
1416 if (j == 0) { | |
1417 if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != | |
1418 SHF_ALLOC) | |
1419 continue; | |
1420 } else { | |
1421 if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != | |
1422 (SHF_ALLOC | SHF_WRITE)) | |
1423 continue; | |
1424 } | |
1425 if (s == interp) { | |
1426 if (k != 0) | |
1427 continue; | |
1428 } else if (s->sh_type == SHT_DYNSYM || | |
1429 s->sh_type == SHT_STRTAB || | |
1430 s->sh_type == SHT_HASH) { | |
1431 if (k != 1) | |
1432 continue; | |
1433 } else if (s->sh_type == SHT_REL) { | |
1434 if (k != 2) | |
1435 continue; | |
1436 } else if (s->sh_type == SHT_NOBITS) { | |
1437 if (k != 4) | |
1438 continue; | |
1439 } else { | |
1440 if (k != 3) | |
1441 continue; | |
1442 } | |
1443 section_order[sh_order_index++] = i; | |
1444 | |
1445 /* section matches: we align it and add its size */ | |
319 | 1446 tmp = addr; |
1447 addr = (addr + s->sh_addralign - 1) & | |
140 | 1448 ~(s->sh_addralign - 1); |
319 | 1449 file_offset += addr - tmp; |
140 | 1450 s->sh_offset = file_offset; |
1451 s->sh_addr = addr; | |
1452 | |
1453 /* update program header infos */ | |
1454 if (ph->p_offset == 0) { | |
1455 ph->p_offset = file_offset; | |
1456 ph->p_vaddr = addr; | |
1457 ph->p_paddr = ph->p_vaddr; | |
1458 } | |
1459 /* update dynamic relocation infos */ | |
1460 if (s->sh_type == SHT_REL) { | |
1461 if (rel_size == 0) | |
1462 rel_addr = addr; | |
1463 rel_size += s->sh_size; | |
1464 } | |
1465 addr += s->sh_size; | |
1466 if (s->sh_type != SHT_NOBITS) | |
1467 file_offset += s->sh_size; | |
1468 } | |
1469 } | |
1470 ph->p_filesz = file_offset - ph->p_offset; | |
1471 ph->p_memsz = addr - ph->p_vaddr; | |
1472 ph++; | |
325 | 1473 if (j == 0) { |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1474 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1475 /* if in the middle of a page, we duplicate the page in |
1476 memory so that one copy is RX and the other is RW */ | |
1477 if ((addr & (ELF_PAGE_SIZE - 1)) != 0) | |
1478 addr += ELF_PAGE_SIZE; | |
1479 } else { | |
1480 addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); | |
1481 file_offset = (file_offset + ELF_PAGE_SIZE - 1) & | |
1482 ~(ELF_PAGE_SIZE - 1); | |
1483 } | |
1484 } | |
140 | 1485 } |
1486 | |
1487 /* if interpreter, then add corresponing program header */ | |
1488 if (interp) { | |
1489 ph = &phdr[0]; | |
1490 | |
1491 ph->p_type = PT_INTERP; | |
1492 ph->p_offset = interp->sh_offset; | |
1493 ph->p_vaddr = interp->sh_addr; | |
1494 ph->p_paddr = ph->p_vaddr; | |
1495 ph->p_filesz = interp->sh_size; | |
1496 ph->p_memsz = interp->sh_size; | |
1497 ph->p_flags = PF_R; | |
1498 ph->p_align = interp->sh_addralign; | |
1499 } | |
1500 | |
1501 /* if dynamic section, then add corresponing program header */ | |
1502 if (dynamic) { | |
1503 Elf32_Sym *sym_end; | |
1504 | |
1505 ph = &phdr[phnum - 1]; | |
1506 | |
1507 ph->p_type = PT_DYNAMIC; | |
1508 ph->p_offset = dynamic->sh_offset; | |
1509 ph->p_vaddr = dynamic->sh_addr; | |
1510 ph->p_paddr = ph->p_vaddr; | |
1511 ph->p_filesz = dynamic->sh_size; | |
1512 ph->p_memsz = dynamic->sh_size; | |
1513 ph->p_flags = PF_R | PF_W; | |
1514 ph->p_align = dynamic->sh_addralign; | |
1515 | |
1516 /* put GOT dynamic section address */ | |
174 | 1517 put32(s1->got->data, dynamic->sh_addr); |
140 | 1518 |
228 | 1519 /* relocate the PLT */ |
1520 if (file_type == TCC_OUTPUT_EXE) { | |
1521 uint8_t *p, *p_end; | |
1522 | |
1523 p = s1->plt->data; | |
1524 p_end = p + s1->plt->data_offset; | |
255 | 1525 if (p < p_end) { |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1526 #if defined(TINYCC_TARGET_I386) |
228 | 1527 put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
255 | 1528 put32(p + 8, get32(p + 8) + s1->got->sh_addr); |
228 | 1529 p += 16; |
255 | 1530 while (p < p_end) { |
1531 put32(p + 2, get32(p + 2) + s1->got->sh_addr); | |
1532 p += 16; | |
1533 } | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1534 #elif defined(TINYCC_TARGET_ARM) |
295 | 1535 int x; |
1536 x=s1->got->sh_addr - s1->plt->sh_addr - 12; | |
1537 p +=16; | |
1538 while (p < p_end) { | |
1539 put32(p + 12, x + get32(p + 12) + s1->plt->data - p); | |
1540 p += 16; | |
1541 } | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1542 #elif defined(TINYCC_TARGET_C67) |
305 | 1543 /* XXX: TODO */ |
295 | 1544 #else |
1545 #error unsupported CPU | |
1546 #endif | |
228 | 1547 } |
1548 } | |
1549 | |
1550 /* relocate symbols in .dynsym */ | |
174 | 1551 sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); |
1552 for(sym = (Elf32_Sym *)s1->dynsym->data + 1; | |
140 | 1553 sym < sym_end; |
1554 sym++) { | |
1555 if (sym->st_shndx == SHN_UNDEF) { | |
228 | 1556 /* relocate to the PLT if the symbol corresponds |
1557 to a PLT entry */ | |
1558 if (sym->st_value) | |
1559 sym->st_value += s1->plt->sh_addr; | |
140 | 1560 } else if (sym->st_shndx < SHN_LORESERVE) { |
1561 /* do symbol relocation */ | |
174 | 1562 sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
140 | 1563 } |
1564 } | |
228 | 1565 |
140 | 1566 /* put dynamic section entries */ |
1567 dynamic->data_offset = saved_dynamic_data_offset; | |
174 | 1568 put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
140 | 1569 put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); |
174 | 1570 put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
140 | 1571 put_dt(dynamic, DT_STRSZ, dynstr->data_offset); |
1572 put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); | |
1573 put_dt(dynamic, DT_REL, rel_addr); | |
1574 put_dt(dynamic, DT_RELSZ, rel_size); | |
1575 put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); | |
1576 put_dt(dynamic, DT_NULL, 0); | |
1577 } | |
1578 | |
1579 ehdr.e_phentsize = sizeof(Elf32_Phdr); | |
1580 ehdr.e_phnum = phnum; | |
1581 ehdr.e_phoff = sizeof(Elf32_Ehdr); | |
1582 } | |
1583 | |
1584 /* all other sections come after */ | |
174 | 1585 for(i = 1; i < s1->nb_sections; i++) { |
1586 s = s1->sections[i]; | |
140 | 1587 if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
1588 continue; | |
1589 section_order[sh_order_index++] = i; | |
1590 | |
1591 file_offset = (file_offset + s->sh_addralign - 1) & | |
1592 ~(s->sh_addralign - 1); | |
1593 s->sh_offset = file_offset; | |
1594 if (s->sh_type != SHT_NOBITS) | |
1595 file_offset += s->sh_size; | |
1596 } | |
1597 | |
1598 /* if building executable or DLL, then relocate each section | |
1599 except the GOT which is already relocated */ | |
1600 if (file_type != TCC_OUTPUT_OBJ) { | |
174 | 1601 relocate_syms(s1, 0); |
1602 | |
1603 if (s1->nb_errors != 0) { | |
1604 fail: | |
1605 ret = -1; | |
1606 goto the_end; | |
1607 } | |
140 | 1608 |
1609 /* relocate sections */ | |
1610 /* XXX: ignore sections with allocated relocations ? */ | |
174 | 1611 for(i = 1; i < s1->nb_sections; i++) { |
1612 s = s1->sections[i]; | |
1613 if (s->reloc && s != s1->got) | |
140 | 1614 relocate_section(s1, s); |
1615 } | |
1616 | |
1617 /* relocate relocation entries if the relocation tables are | |
1618 allocated in the executable */ | |
174 | 1619 for(i = 1; i < s1->nb_sections; i++) { |
1620 s = s1->sections[i]; | |
140 | 1621 if ((s->sh_flags & SHF_ALLOC) && |
1622 s->sh_type == SHT_REL) { | |
174 | 1623 relocate_rel(s1, s); |
140 | 1624 } |
1625 } | |
1626 | |
1627 /* get entry point address */ | |
1628 if (file_type == TCC_OUTPUT_EXE) | |
283 | 1629 ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start"); |
140 | 1630 else |
1631 ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ | |
1632 } | |
1633 | |
1634 /* write elf file */ | |
1635 if (file_type == TCC_OUTPUT_OBJ) | |
1636 mode = 0666; | |
1637 else | |
1638 mode = 0777; | |
325 | 1639 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
174 | 1640 if (fd < 0) { |
1641 error_noabort("could not write '%s'", filename); | |
1642 goto fail; | |
1643 } | |
325 | 1644 f = fdopen(fd, "wb"); |
1645 | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1646 #ifdef TINYCC_TARGET_COFF |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1647 if (tccg_output_format == TCC_OUTPUT_FORMAT_COFF) { |
325 | 1648 tcc_output_coff(s1, f); |
1649 } else | |
1650 #endif | |
554
8c020de0af57
Fix earlier options.c break-up by migrating some stuff from tcc.h to tinycc.h.
Rob Landley <rob@landley.net>
parents:
553
diff
changeset
|
1651 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1652 sort_syms(s1, symtab_section); |
1653 | |
1654 /* align to 4 */ | |
1655 file_offset = (file_offset + 3) & -4; | |
1656 | |
1657 /* fill header */ | |
1658 ehdr.e_ident[0] = ELFMAG0; | |
1659 ehdr.e_ident[1] = ELFMAG1; | |
1660 ehdr.e_ident[2] = ELFMAG2; | |
1661 ehdr.e_ident[3] = ELFMAG3; | |
1662 ehdr.e_ident[4] = ELFCLASS32; | |
1663 ehdr.e_ident[5] = ELFDATA2LSB; | |
1664 ehdr.e_ident[6] = EV_CURRENT; | |
1665 #ifdef __FreeBSD__ | |
1666 ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | |
1667 #endif | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1668 #ifdef TINYCC_TARGET_ARM |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1669 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1670 ehdr.e_ident[EI_OSABI] = 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1671 ehdr.e_flags = 4 << 24; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1672 #else |
325 | 1673 ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
1674 #endif | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1675 #endif |
325 | 1676 switch(file_type) { |
1677 default: | |
1678 case TCC_OUTPUT_EXE: | |
1679 ehdr.e_type = ET_EXEC; | |
1680 break; | |
1681 case TCC_OUTPUT_DLL: | |
1682 ehdr.e_type = ET_DYN; | |
1683 break; | |
1684 case TCC_OUTPUT_OBJ: | |
1685 ehdr.e_type = ET_REL; | |
1686 break; | |
140 | 1687 } |
325 | 1688 ehdr.e_machine = EM_TCC_TARGET; |
1689 ehdr.e_version = EV_CURRENT; | |
1690 ehdr.e_shoff = file_offset; | |
1691 ehdr.e_ehsize = sizeof(Elf32_Ehdr); | |
1692 ehdr.e_shentsize = sizeof(Elf32_Shdr); | |
1693 ehdr.e_shnum = shnum; | |
1694 ehdr.e_shstrndx = shnum - 1; | |
1695 | |
1696 fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f); | |
1697 fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f); | |
1698 offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); | |
1699 | |
1700 for(i=1;i<s1->nb_sections;i++) { | |
1701 s = s1->sections[section_order[i]]; | |
1702 if (s->sh_type != SHT_NOBITS) { | |
1703 while (offset < s->sh_offset) { | |
1704 fputc(0, f); | |
1705 offset++; | |
1706 } | |
1707 size = s->sh_size; | |
1708 fwrite(s->data, 1, size, f); | |
1709 offset += size; | |
1710 } | |
1711 } | |
1712 | |
1713 /* output section headers */ | |
1714 while (offset < ehdr.e_shoff) { | |
1715 fputc(0, f); | |
1716 offset++; | |
1717 } | |
140 | 1718 |
325 | 1719 for(i=0;i<s1->nb_sections;i++) { |
1720 sh = &shdr; | |
1721 memset(sh, 0, sizeof(Elf32_Shdr)); | |
1722 s = s1->sections[i]; | |
1723 if (s) { | |
1724 sh->sh_name = s->sh_name; | |
1725 sh->sh_type = s->sh_type; | |
1726 sh->sh_flags = s->sh_flags; | |
1727 sh->sh_entsize = s->sh_entsize; | |
1728 sh->sh_info = s->sh_info; | |
1729 if (s->link) | |
1730 sh->sh_link = s->link->sh_num; | |
1731 sh->sh_addralign = s->sh_addralign; | |
1732 sh->sh_addr = s->sh_addr; | |
1733 sh->sh_offset = s->sh_offset; | |
1734 sh->sh_size = s->sh_size; | |
1735 } | |
1736 fwrite(sh, 1, sizeof(Elf32_Shdr), f); | |
140 | 1737 } |
325 | 1738 } else { |
1739 tcc_output_binary(s1, f, section_order); | |
140 | 1740 } |
1741 fclose(f); | |
1742 | |
174 | 1743 ret = 0; |
1744 the_end: | |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
1745 free(s1->symtab_to_dynsym); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
1746 free(section_order); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
1747 free(phdr); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
1748 free(s1->got_offsets); |
174 | 1749 return ret; |
140 | 1750 } |
1751 | |
1752 static void *load_data(int fd, unsigned long file_offset, unsigned long size) | |
1753 { | |
1754 void *data; | |
1755 | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1756 data = xmalloc(size); |
140 | 1757 lseek(fd, file_offset, SEEK_SET); |
1758 read(fd, data, size); | |
1759 return data; | |
1760 } | |
1761 | |
1762 typedef struct SectionMergeInfo { | |
1763 Section *s; /* corresponding existing section */ | |
1764 unsigned long offset; /* offset of the new section in the existing section */ | |
287 | 1765 uint8_t new_section; /* true if section 's' was added */ |
1766 uint8_t link_once; /* true if link once section */ | |
140 | 1767 } SectionMergeInfo; |
1768 | |
1769 /* load an object file and merge it with current files */ | |
1770 /* XXX: handle correctly stab (debug) info */ | |
1771 static int tcc_load_object_file(TCCState *s1, | |
1772 int fd, unsigned long file_offset) | |
1773 { | |
1774 Elf32_Ehdr ehdr; | |
1775 Elf32_Shdr *shdr, *sh; | |
174 | 1776 int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
140 | 1777 unsigned char *strsec, *strtab; |
1778 int *old_to_new_syms; | |
1779 char *sh_name, *name; | |
1780 SectionMergeInfo *sm_table, *sm; | |
1781 Elf32_Sym *sym, *symtab; | |
1782 Elf32_Rel *rel, *rel_end; | |
1783 Section *s; | |
1784 | |
1785 if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) | |
174 | 1786 goto fail1; |
140 | 1787 if (ehdr.e_ident[0] != ELFMAG0 || |
1788 ehdr.e_ident[1] != ELFMAG1 || | |
1789 ehdr.e_ident[2] != ELFMAG2 || | |
1790 ehdr.e_ident[3] != ELFMAG3) | |
174 | 1791 goto fail1; |
140 | 1792 /* test if object file */ |
1793 if (ehdr.e_type != ET_REL) | |
174 | 1794 goto fail1; |
140 | 1795 /* test CPU specific stuff */ |
1796 if (ehdr.e_ident[5] != ELFDATA2LSB || | |
295 | 1797 ehdr.e_machine != EM_TCC_TARGET) { |
174 | 1798 fail1: |
1799 error_noabort("invalid object file"); | |
1800 return -1; | |
140 | 1801 } |
1802 /* read sections */ | |
1803 shdr = load_data(fd, file_offset + ehdr.e_shoff, | |
1804 sizeof(Elf32_Shdr) * ehdr.e_shnum); | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1805 sm_table = xzmalloc(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
140 | 1806 |
1807 /* load section names */ | |
1808 sh = &shdr[ehdr.e_shstrndx]; | |
1809 strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1810 | |
1811 /* load symtab and strtab */ | |
174 | 1812 old_to_new_syms = NULL; |
140 | 1813 symtab = NULL; |
1814 strtab = NULL; | |
1815 nb_syms = 0; | |
1816 for(i = 1; i < ehdr.e_shnum; i++) { | |
1817 sh = &shdr[i]; | |
1818 if (sh->sh_type == SHT_SYMTAB) { | |
174 | 1819 if (symtab) { |
1820 error_noabort("object must contain only one symtab"); | |
1821 fail: | |
1822 ret = -1; | |
1823 goto the_end; | |
1824 } | |
140 | 1825 nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
1826 symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1827 sm_table[i].s = symtab_section; | |
1828 | |
1829 /* now load strtab */ | |
1830 sh = &shdr[sh->sh_link]; | |
1831 strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1832 } | |
1833 } | |
1834 | |
1835 /* now examine each section and try to merge its content with the | |
1836 ones in memory */ | |
1837 for(i = 1; i < ehdr.e_shnum; i++) { | |
1838 /* no need to examine section name strtab */ | |
1839 if (i == ehdr.e_shstrndx) | |
1840 continue; | |
1841 sh = &shdr[i]; | |
1842 sh_name = strsec + sh->sh_name; | |
1843 /* ignore sections types we do not handle */ | |
1844 if (sh->sh_type != SHT_PROGBITS && | |
1845 sh->sh_type != SHT_REL && | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1846 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1847 sh->sh_type != SHT_ARM_EXIDX && |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1848 #endif |
140 | 1849 sh->sh_type != SHT_NOBITS) |
1850 continue; | |
1851 if (sh->sh_addralign < 1) | |
1852 sh->sh_addralign = 1; | |
1853 /* find corresponding section, if any */ | |
174 | 1854 for(j = 1; j < s1->nb_sections;j++) { |
1855 s = s1->sections[j]; | |
287 | 1856 if (!strcmp(s->name, sh_name)) { |
1857 if (!strncmp(sh_name, ".gnu.linkonce", | |
1858 sizeof(".gnu.linkonce") - 1)) { | |
1859 /* if a 'linkonce' section is already present, we | |
1860 do not add it again. It is a little tricky as | |
1861 symbols can still be defined in | |
1862 it. */ | |
1863 sm_table[i].link_once = 1; | |
1864 goto next; | |
1865 } else { | |
1866 goto found; | |
1867 } | |
1868 } | |
140 | 1869 } |
1870 /* not found: create new section */ | |
174 | 1871 s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags); |
140 | 1872 /* take as much info as possible from the section. sh_link and |
1873 sh_info will be updated later */ | |
1874 s->sh_addralign = sh->sh_addralign; | |
1875 s->sh_entsize = sh->sh_entsize; | |
1876 sm_table[i].new_section = 1; | |
1877 found: | |
174 | 1878 if (sh->sh_type != s->sh_type) { |
1879 error_noabort("invalid section type"); | |
140 | 1880 goto fail; |
174 | 1881 } |
140 | 1882 |
1883 /* align start of section */ | |
1884 offset = s->data_offset; | |
1885 size = sh->sh_addralign - 1; | |
1886 offset = (offset + size) & ~size; | |
1887 if (sh->sh_addralign > s->sh_addralign) | |
1888 s->sh_addralign = sh->sh_addralign; | |
1889 s->data_offset = offset; | |
1890 sm_table[i].offset = offset; | |
1891 sm_table[i].s = s; | |
1892 /* concatenate sections */ | |
1893 size = sh->sh_size; | |
1894 if (sh->sh_type != SHT_NOBITS) { | |
1895 unsigned char *ptr; | |
1896 lseek(fd, file_offset + sh->sh_offset, SEEK_SET); | |
151 | 1897 ptr = section_ptr_add(s, size); |
140 | 1898 read(fd, ptr, size); |
151 | 1899 } else { |
1900 s->data_offset += size; | |
140 | 1901 } |
287 | 1902 next: ; |
140 | 1903 } |
1904 | |
1905 /* second short pass to update sh_link and sh_info fields of new | |
1906 sections */ | |
1907 for(i = 1; i < ehdr.e_shnum; i++) { | |
1908 s = sm_table[i].s; | |
1909 if (!s || !sm_table[i].new_section) | |
1910 continue; | |
1911 sh = &shdr[i]; | |
1912 if (sh->sh_link > 0) | |
1913 s->link = sm_table[sh->sh_link].s; | |
1914 if (sh->sh_type == SHT_REL) { | |
1915 s->sh_info = sm_table[sh->sh_info].s->sh_num; | |
1916 /* update backward link */ | |
174 | 1917 s1->sections[s->sh_info]->reloc = s; |
140 | 1918 } |
1919 } | |
396
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1920 sm = sm_table; |
140 | 1921 |
1922 /* resolve symbols */ | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1923 old_to_new_syms = xzmalloc(nb_syms * sizeof(int)); |
140 | 1924 |
1925 sym = symtab + 1; | |
1926 for(i = 1; i < nb_syms; i++, sym++) { | |
1927 if (sym->st_shndx != SHN_UNDEF && | |
1928 sym->st_shndx < SHN_LORESERVE) { | |
1929 sm = &sm_table[sym->st_shndx]; | |
287 | 1930 if (sm->link_once) { |
1931 /* if a symbol is in a link once section, we use the | |
1932 already defined symbol. It is very important to get | |
1933 correct relocations */ | |
1934 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { | |
1935 name = strtab + sym->st_name; | |
1936 sym_index = find_elf_sym(symtab_section, name); | |
1937 if (sym_index) | |
1938 old_to_new_syms[i] = sym_index; | |
1939 } | |
1940 continue; | |
1941 } | |
140 | 1942 /* if no corresponding section added, no need to add symbol */ |
1943 if (!sm->s) | |
1944 continue; | |
1945 /* convert section number */ | |
1946 sym->st_shndx = sm->s->sh_num; | |
1947 /* offset value */ | |
1948 sym->st_value += sm->offset; | |
1949 } | |
1950 /* add symbol */ | |
1951 name = strtab + sym->st_name; | |
1952 sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, | |
356 | 1953 sym->st_info, sym->st_other, |
1954 sym->st_shndx, name); | |
140 | 1955 old_to_new_syms[i] = sym_index; |
1956 } | |
1957 | |
1958 /* third pass to patch relocation entries */ | |
1959 for(i = 1; i < ehdr.e_shnum; i++) { | |
1960 s = sm_table[i].s; | |
1961 if (!s) | |
1962 continue; | |
1963 sh = &shdr[i]; | |
1964 offset = sm_table[i].offset; | |
1965 switch(s->sh_type) { | |
1966 case SHT_REL: | |
1967 /* take relocation offset information */ | |
1968 offseti = sm_table[sh->sh_info].offset; | |
1969 rel_end = (Elf32_Rel *)(s->data + s->data_offset); | |
1970 for(rel = (Elf32_Rel *)(s->data + offset); | |
1971 rel < rel_end; | |
1972 rel++) { | |
1973 int type; | |
1974 unsigned sym_index; | |
1975 /* convert symbol index */ | |
1976 type = ELF32_R_TYPE(rel->r_info); | |
1977 sym_index = ELF32_R_SYM(rel->r_info); | |
1978 /* NOTE: only one symtab assumed */ | |
1979 if (sym_index >= nb_syms) | |
1980 goto invalid_reloc; | |
1981 sym_index = old_to_new_syms[sym_index]; | |
396
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1982 /* ignore link_once in rel section. */ |
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1983 if (!sym_index && !sm->link_once) { |
140 | 1984 invalid_reloc: |
396
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1985 error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", |
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1986 i, strsec + sh->sh_name, rel->r_offset); |
174 | 1987 goto fail; |
140 | 1988 } |
1989 rel->r_info = ELF32_R_INFO(sym_index, type); | |
1990 /* offset the relocation offset */ | |
1991 rel->r_offset += offseti; | |
1992 } | |
1993 break; | |
1994 default: | |
1995 break; | |
1996 } | |
1997 } | |
174 | 1998 |
1999 ret = 0; | |
2000 the_end: | |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2001 free(symtab); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2002 free(strtab); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2003 free(old_to_new_syms); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2004 free(sm_table); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2005 free(strsec); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2006 free(shdr); |
174 | 2007 return ret; |
140 | 2008 } |
2009 | |
2010 #define ARMAG "!<arch>\012" /* For COFF and a.out archives */ | |
2011 | |
2012 typedef struct ArchiveHeader { | |
2013 char ar_name[16]; /* name of this member */ | |
2014 char ar_date[12]; /* file mtime */ | |
2015 char ar_uid[6]; /* owner uid; printed as decimal */ | |
2016 char ar_gid[6]; /* owner gid; printed as decimal */ | |
2017 char ar_mode[8]; /* file mode, printed as octal */ | |
2018 char ar_size[10]; /* file size, printed as decimal */ | |
2019 char ar_fmag[2]; /* should contain ARFMAG */ | |
2020 } ArchiveHeader; | |
2021 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2022 static int get_be32(uint8_t *b) |
259 | 2023 { |
2024 return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); | |
2025 } | |
2026 | |
2027 /* load only the objects which resolve undefined symbols */ | |
2028 static int tcc_load_alacarte(TCCState *s1, int fd, int size) | |
2029 { | |
2030 int i, bound, nsyms, sym_index, off, ret; | |
2031 uint8_t *data; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2032 char *ar_names, *p; |
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2033 uint8_t *ar_index; |
259 | 2034 Elf32_Sym *sym; |
2035 | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
2036 data = xmalloc(size); |
259 | 2037 if (read(fd, data, size) != size) |
2038 goto fail; | |
2039 nsyms = get_be32(data); | |
2040 ar_index = data + 4; | |
2041 ar_names = ar_index + nsyms * 4; | |
2042 | |
2043 do { | |
2044 bound = 0; | |
2045 for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { | |
2046 sym_index = find_elf_sym(symtab_section, p); | |
2047 if(sym_index) { | |
2048 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
2049 if(sym->st_shndx == SHN_UNDEF) { | |
2050 off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); | |
2051 #if 0 | |
2052 printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); | |
2053 #endif | |
2054 ++bound; | |
2055 lseek(fd, off, SEEK_SET); | |
2056 if(tcc_load_object_file(s1, fd, off) < 0) { | |
2057 fail: | |
2058 ret = -1; | |
2059 goto the_end; | |
2060 } | |
2061 } | |
2062 } | |
2063 } | |
2064 } while(bound); | |
2065 ret = 0; | |
2066 the_end: | |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2067 free(data); |
259 | 2068 return ret; |
2069 } | |
2070 | |
140 | 2071 /* load a '.a' file */ |
2072 static int tcc_load_archive(TCCState *s1, int fd) | |
2073 { | |
2074 ArchiveHeader hdr; | |
2075 char ar_size[11]; | |
2076 char ar_name[17]; | |
2077 char magic[8]; | |
2078 int size, len, i; | |
2079 unsigned long file_offset; | |
2080 | |
2081 /* skip magic which was already checked */ | |
2082 read(fd, magic, sizeof(magic)); | |
2083 | |
2084 for(;;) { | |
2085 len = read(fd, &hdr, sizeof(hdr)); | |
2086 if (len == 0) | |
2087 break; | |
174 | 2088 if (len != sizeof(hdr)) { |
2089 error_noabort("invalid archive"); | |
2090 return -1; | |
2091 } | |
140 | 2092 memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
2093 ar_size[sizeof(hdr.ar_size)] = '\0'; | |
2094 size = strtol(ar_size, NULL, 0); | |
2095 memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name)); | |
2096 for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { | |
2097 if (ar_name[i] != ' ') | |
2098 break; | |
2099 } | |
2100 ar_name[i + 1] = '\0'; | |
2101 // printf("name='%s' size=%d %s\n", ar_name, size, ar_size); | |
2102 file_offset = lseek(fd, 0, SEEK_CUR); | |
259 | 2103 /* align to even */ |
2104 size = (size + 1) & ~1; | |
2105 if (!strcmp(ar_name, "/")) { | |
2106 /* coff symbol table : we handle it */ | |
2107 if(s1->alacarte_link) | |
2108 return tcc_load_alacarte(s1, fd, size); | |
2109 } else if (!strcmp(ar_name, "//") || | |
2110 !strcmp(ar_name, "__.SYMDEF") || | |
2111 !strcmp(ar_name, "__.SYMDEF/") || | |
2112 !strcmp(ar_name, "ARFILENAMES/")) { | |
140 | 2113 /* skip symbol table or archive names */ |
2114 } else { | |
174 | 2115 if (tcc_load_object_file(s1, fd, file_offset) < 0) |
2116 return -1; | |
140 | 2117 } |
2118 lseek(fd, file_offset + size, SEEK_SET); | |
2119 } | |
2120 return 0; | |
2121 } | |
2122 | |
2123 /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL | |
2124 is referenced by the user (so it should be added as DT_NEEDED in | |
2125 the generated ELF file) */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2126 static int tcc_load_dll(TCCState *s1, int fd, char *filename, int level) |
140 | 2127 { |
2128 Elf32_Ehdr ehdr; | |
2129 Elf32_Shdr *shdr, *sh, *sh1; | |
394 | 2130 int i, j, nb_syms, nb_dts, sym_bind, ret; |
140 | 2131 Elf32_Sym *sym, *dynsym; |
2132 Elf32_Dyn *dt, *dynamic; | |
2133 unsigned char *dynstr; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2134 char *name, *soname, *p; |
140 | 2135 DLLReference *dllref; |
2136 | |
2137 read(fd, &ehdr, sizeof(ehdr)); | |
2138 | |
2139 /* test CPU specific stuff */ | |
2140 if (ehdr.e_ident[5] != ELFDATA2LSB || | |
295 | 2141 ehdr.e_machine != EM_TCC_TARGET) { |
174 | 2142 error_noabort("bad architecture"); |
2143 return -1; | |
2144 } | |
140 | 2145 |
2146 /* read sections */ | |
2147 shdr = load_data(fd, ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); | |
2148 | |
2149 /* load dynamic section and dynamic symbols */ | |
2150 nb_syms = 0; | |
2151 nb_dts = 0; | |
2152 dynamic = NULL; | |
2153 dynsym = NULL; /* avoid warning */ | |
2154 dynstr = NULL; /* avoid warning */ | |
2155 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { | |
2156 switch(sh->sh_type) { | |
2157 case SHT_DYNAMIC: | |
2158 nb_dts = sh->sh_size / sizeof(Elf32_Dyn); | |
2159 dynamic = load_data(fd, sh->sh_offset, sh->sh_size); | |
2160 break; | |
2161 case SHT_DYNSYM: | |
2162 nb_syms = sh->sh_size / sizeof(Elf32_Sym); | |
2163 dynsym = load_data(fd, sh->sh_offset, sh->sh_size); | |
2164 sh1 = &shdr[sh->sh_link]; | |
2165 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); | |
2166 break; | |
2167 default: | |
2168 break; | |
2169 } | |
2170 } | |
2171 | |
2172 /* compute the real library name */ | |
2173 soname = filename; | |
2174 p = strrchr(soname, '/'); | |
2175 if (p) | |
2176 soname = p + 1; | |
2177 | |
2178 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { | |
2179 if (dt->d_tag == DT_SONAME) { | |
2180 soname = dynstr + dt->d_un.d_val; | |
2181 } | |
2182 } | |
2183 | |
2184 /* if the dll is already loaded, do not load it */ | |
174 | 2185 for(i = 0; i < s1->nb_loaded_dlls; i++) { |
2186 dllref = s1->loaded_dlls[i]; | |
140 | 2187 if (!strcmp(soname, dllref->name)) { |
2188 /* but update level if needed */ | |
2189 if (level < dllref->level) | |
2190 dllref->level = level; | |
174 | 2191 ret = 0; |
140 | 2192 goto the_end; |
2193 } | |
2194 } | |
2195 | |
2196 // printf("loading dll '%s'\n", soname); | |
2197 | |
2198 /* add the dll and its level */ | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
2199 dllref = xmalloc(sizeof(DLLReference) + strlen(soname)); |
140 | 2200 dllref->level = level; |
2201 strcpy(dllref->name, soname); | |
174 | 2202 dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
140 | 2203 |
2204 /* add dynamic symbols in dynsym_section */ | |
2205 for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { | |
2206 sym_bind = ELF32_ST_BIND(sym->st_info); | |
2207 if (sym_bind == STB_LOCAL) | |
2208 continue; | |
2209 name = dynstr + sym->st_name; | |
174 | 2210 add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
372 | 2211 sym->st_info, sym->st_other, sym->st_shndx, name); |
140 | 2212 } |
2213 | |
2214 /* load all referenced DLLs */ | |
2215 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { | |
2216 switch(dt->d_tag) { | |
2217 case DT_NEEDED: | |
2218 name = dynstr + dt->d_un.d_val; | |
394 | 2219 for(j = 0; j < s1->nb_loaded_dlls; j++) { |
2220 dllref = s1->loaded_dlls[j]; | |
140 | 2221 if (!strcmp(name, dllref->name)) |
2222 goto already_loaded; | |
2223 } | |
174 | 2224 if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
2225 error_noabort("referenced dll '%s' not found", name); | |
2226 ret = -1; | |
2227 goto the_end; | |
2228 } | |
140 | 2229 already_loaded: |
2230 break; | |
2231 } | |
2232 } | |
174 | 2233 ret = 0; |
140 | 2234 the_end: |
481
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2235 free(dynstr); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2236 free(dynsym); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2237 free(dynamic); |
0f5c38ddf450
Remove MEM_DEBUG and now-useless tcc_free() wrapper. Now, would anyone like to
Rob Landley <rob@landley.net>
parents:
479
diff
changeset
|
2238 free(shdr); |
174 | 2239 return ret; |
140 | 2240 } |
2241 | |
191 | 2242 #define LD_TOK_NAME 256 |
2243 #define LD_TOK_EOF (-1) | |
2244 | |
2245 /* return next ld script token */ | |
2246 static int ld_next(TCCState *s1, char *name, int name_size) | |
140 | 2247 { |
191 | 2248 int c; |
140 | 2249 char *q; |
2250 | |
191 | 2251 redo: |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2252 switch(fch) { |
191 | 2253 case ' ': |
2254 case '\t': | |
2255 case '\f': | |
2256 case '\v': | |
2257 case '\r': | |
2258 case '\n': | |
2259 inp(); | |
2260 goto redo; | |
2261 case '/': | |
2262 minp(); | |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2263 if (fch == '*') { |
230 | 2264 file->buf_ptr = parse_comment(file->buf_ptr); |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2265 fch = file->buf_ptr[0]; |
191 | 2266 goto redo; |
2267 } else { | |
2268 q = name; | |
2269 *q++ = '/'; | |
2270 goto parse_name; | |
2271 } | |
2272 break; | |
2273 case 'a' ... 'z': | |
2274 case 'A' ... 'Z': | |
2275 case '_': | |
2276 case '\\': | |
2277 case '.': | |
2278 case '$': | |
2279 case '~': | |
2280 q = name; | |
2281 parse_name: | |
2282 for(;;) { | |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2283 if (!((fch >= 'a' && fch <= 'z') || |
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2284 (fch >= 'A' && fch <= 'Z') || |
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2285 (fch >= '0' && fch <= '9') || |
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2286 strchr("/.-_+=$:\\,~", fch))) |
191 | 2287 break; |
2288 if ((q - name) < name_size - 1) { | |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2289 *q++ = fch; |
191 | 2290 } |
2291 minp(); | |
2292 } | |
2293 *q = '\0'; | |
2294 c = LD_TOK_NAME; | |
2295 break; | |
2296 case CH_EOF: | |
2297 c = LD_TOK_EOF; | |
2298 break; | |
2299 default: | |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2300 c = fch; |
191 | 2301 inp(); |
2302 break; | |
140 | 2303 } |
191 | 2304 #if 0 |
2305 printf("tok=%c %d\n", c, c); | |
2306 if (c == LD_TOK_NAME) | |
2307 printf(" name=%s\n", name); | |
2308 #endif | |
2309 return c; | |
140 | 2310 } |
191 | 2311 |
383 | 2312 static int ld_add_file_list(TCCState *s1, int as_needed) |
2313 { | |
2314 char filename[1024]; | |
2315 int t, ret; | |
2316 | |
2317 t = ld_next(s1, filename, sizeof(filename)); | |
2318 if (t != '(') | |
2319 expect("("); | |
2320 t = ld_next(s1, filename, sizeof(filename)); | |
2321 for(;;) { | |
2322 if (t == LD_TOK_EOF) { | |
2323 error_noabort("unexpected end of file"); | |
2324 return -1; | |
2325 } else if (t == ')') { | |
2326 break; | |
2327 } else if (t != LD_TOK_NAME) { | |
2328 error_noabort("filename expected"); | |
2329 return -1; | |
2330 } | |
2331 if (!strcmp(filename, "AS_NEEDED")) { | |
2332 ret = ld_add_file_list(s1, 1); | |
2333 if (ret) | |
2334 return ret; | |
2335 } else { | |
2336 /* TODO: Implement AS_NEEDED support. Ignore it for now */ | |
564
d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
Rob Landley <rob@landley.net>
parents:
555
diff
changeset
|
2337 if (!as_needed) { |
d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
Rob Landley <rob@landley.net>
parents:
555
diff
changeset
|
2338 if (*filename=='/') tcc_add_file(s1, filename); |
d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
Rob Landley <rob@landley.net>
parents:
555
diff
changeset
|
2339 else tcc_add_dll(s1, filename, AFF_PRINT_ERROR); |
d89a6822b7e0
Use library search path for crt?.o, and for ld script libraries with no path.
Rob Landley <rob@landley.net>
parents:
555
diff
changeset
|
2340 } |
383 | 2341 } |
2342 t = ld_next(s1, filename, sizeof(filename)); | |
2343 if (t == ',') { | |
2344 t = ld_next(s1, filename, sizeof(filename)); | |
2345 } | |
2346 } | |
2347 return 0; | |
2348 } | |
2349 | |
140 | 2350 /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
2351 files */ | |
2352 static int tcc_load_ldscript(TCCState *s1) | |
2353 { | |
2354 char cmd[64]; | |
2355 char filename[1024]; | |
383 | 2356 int t, ret; |
140 | 2357 |
479
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2358 //fch = file->buf_ptr[0]; |
7909d3c7e712
Replace global "ch" with "fch" so it's slightly easier to grep for. (It's the
Rob Landley <rob@landley.net>
parents:
469
diff
changeset
|
2359 fch = handle_eob(); |
140 | 2360 for(;;) { |
191 | 2361 t = ld_next(s1, cmd, sizeof(cmd)); |
2362 if (t == LD_TOK_EOF) | |
140 | 2363 return 0; |
191 | 2364 else if (t != LD_TOK_NAME) |
140 | 2365 return -1; |
2366 if (!strcmp(cmd, "INPUT") || | |
2367 !strcmp(cmd, "GROUP")) { | |
383 | 2368 ret = ld_add_file_list(s1, 0); |
2369 if (ret) | |
2370 return ret; | |
248 | 2371 } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
2372 !strcmp(cmd, "TARGET")) { | |
2373 /* ignore some commands */ | |
2374 t = ld_next(s1, cmd, sizeof(cmd)); | |
2375 if (t != '(') | |
2376 expect("("); | |
2377 for(;;) { | |
2378 t = ld_next(s1, filename, sizeof(filename)); | |
2379 if (t == LD_TOK_EOF) { | |
2380 error_noabort("unexpected end of file"); | |
2381 return -1; | |
2382 } else if (t == ')') { | |
2383 break; | |
2384 } | |
2385 } | |
140 | 2386 } else { |
2387 return -1; | |
2388 } | |
2389 } | |
2390 return 0; | |
2391 } |