Mercurial > hg > tinycc
annotate tccelf.c @ 570:c42c2145d359
The dynamic linker location belongs in configure, move it there.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 15 Mar 2008 21:23:24 -0500 |
parents | d89a6822b7e0 |
children | 6912ed120df3 |
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 */ | |
570
c42c2145d359
The dynamic linker location belongs in configure, move it there.
Rob Landley <rob@landley.net>
parents:
564
diff
changeset
|
1082 static char elf_interp[] = CC_DYNAMIC_LINKER; |
140 | 1083 |
325 | 1084 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
|
1085 int *section_order) |
325 | 1086 { |
1087 Section *s; | |
1088 int i, offset, size; | |
1089 | |
1090 offset = 0; | |
1091 for(i=1;i<s1->nb_sections;i++) { | |
1092 s = s1->sections[section_order[i]]; | |
1093 if (s->sh_type != SHT_NOBITS && | |
1094 (s->sh_flags & SHF_ALLOC)) { | |
1095 while (offset < s->sh_offset) { | |
1096 fputc(0, f); | |
1097 offset++; | |
1098 } | |
1099 size = s->sh_size; | |
1100 fwrite(s->data, 1, size, f); | |
1101 offset += size; | |
1102 } | |
1103 } | |
1104 } | |
1105 | |
140 | 1106 /* output an ELF file */ |
1107 /* XXX: suppress unneeded sections */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1108 int tcc_output_file(TCCState *s1, char *filename) |
140 | 1109 { |
1110 Elf32_Ehdr ehdr; | |
1111 FILE *f; | |
174 | 1112 int fd, mode, ret; |
140 | 1113 int *section_order; |
1114 int shnum, i, phnum, file_offset, offset, size, j, tmp, sh_order_index, k; | |
1115 unsigned long addr; | |
1116 Section *strsec, *s; | |
1117 Elf32_Shdr shdr, *sh; | |
1118 Elf32_Phdr *phdr, *ph; | |
228 | 1119 Section *interp, *dynamic, *dynstr; |
140 | 1120 unsigned long saved_dynamic_data_offset; |
1121 Elf32_Sym *sym; | |
1122 int type, file_type; | |
1123 unsigned long rel_addr, rel_size; | |
1124 | |
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
|
1125 file_type = tccg_output_type; |
174 | 1126 s1->nb_errors = 0; |
140 | 1127 |
319 | 1128 if (file_type != TCC_OUTPUT_OBJ) { |
140 | 1129 tcc_add_runtime(s1); |
319 | 1130 } |
140 | 1131 |
174 | 1132 phdr = NULL; |
1133 section_order = NULL; | |
140 | 1134 interp = NULL; |
1135 dynamic = NULL; | |
1136 dynstr = NULL; /* avoid warning */ | |
1137 saved_dynamic_data_offset = 0; /* avoid warning */ | |
174 | 1138 |
140 | 1139 if (file_type != TCC_OUTPUT_OBJ) { |
325 | 1140 relocate_common_syms(); |
1141 | |
1142 tcc_add_linker_symbols(s1); | |
140 | 1143 |
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
|
1144 if (!tccg_static_link) { |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
1145 char *name; |
140 | 1146 int sym_index, index; |
1147 Elf32_Sym *esym, *sym_end; | |
1148 | |
1149 if (file_type == TCC_OUTPUT_EXE) { | |
1150 char *ptr; | |
1151 /* add interpreter section only if executable */ | |
174 | 1152 interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
140 | 1153 interp->sh_addralign = 1; |
1154 ptr = section_ptr_add(interp, sizeof(elf_interp)); | |
1155 strcpy(ptr, elf_interp); | |
1156 } | |
1157 | |
1158 /* add dynamic symbol table */ | |
174 | 1159 s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
1160 ".dynstr", | |
1161 ".hash", SHF_ALLOC); | |
1162 dynstr = s1->dynsym->link; | |
140 | 1163 |
1164 /* add dynamic section */ | |
174 | 1165 dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
140 | 1166 SHF_ALLOC | SHF_WRITE); |
1167 dynamic->link = dynstr; | |
1168 dynamic->sh_entsize = sizeof(Elf32_Dyn); | |
1169 | |
1170 /* add PLT */ | |
228 | 1171 s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
1172 SHF_ALLOC | SHF_EXECINSTR); | |
1173 s1->plt->sh_entsize = 4; | |
140 | 1174 |
174 | 1175 build_got(s1); |
140 | 1176 |
1177 /* scan for undefined symbols and see if they are in the | |
1178 dynamic symbols. If a symbol STT_FUNC is found, then we | |
1179 add it in the PLT. If a symbol STT_OBJECT is found, we | |
1180 add it in the .bss section with a suitable relocation */ | |
1181 sym_end = (Elf32_Sym *)(symtab_section->data + | |
1182 symtab_section->data_offset); | |
1183 if (file_type == TCC_OUTPUT_EXE) { | |
1184 for(sym = (Elf32_Sym *)symtab_section->data + 1; | |
1185 sym < sym_end; | |
1186 sym++) { | |
1187 if (sym->st_shndx == SHN_UNDEF) { | |
1188 name = symtab_section->link->data + sym->st_name; | |
174 | 1189 sym_index = find_elf_sym(s1->dynsymtab_section, name); |
140 | 1190 if (sym_index) { |
174 | 1191 esym = &((Elf32_Sym *)s1->dynsymtab_section->data)[sym_index]; |
140 | 1192 type = ELF32_ST_TYPE(esym->st_info); |
1193 if (type == STT_FUNC) { | |
295 | 1194 put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
140 | 1195 esym->st_info, |
1196 sym - (Elf32_Sym *)symtab_section->data); | |
1197 } else if (type == STT_OBJECT) { | |
1198 unsigned long offset; | |
1199 offset = bss_section->data_offset; | |
1200 /* XXX: which alignment ? */ | |
272 | 1201 offset = (offset + 16 - 1) & -16; |
174 | 1202 index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
140 | 1203 esym->st_info, 0, |
1204 bss_section->sh_num, name); | |
174 | 1205 put_elf_reloc(s1->dynsym, bss_section, |
295 | 1206 offset, R_COPY, index); |
140 | 1207 offset += esym->st_size; |
1208 bss_section->data_offset = offset; | |
1209 } | |
1210 } else { | |
1211 /* STB_WEAK undefined symbols are accepted */ | |
1212 /* XXX: _fp_hw seems to be part of the ABI, so we ignore | |
1213 it */ | |
1214 if (ELF32_ST_BIND(sym->st_info) == STB_WEAK || | |
1215 !strcmp(name, "_fp_hw")) { | |
1216 } else { | |
174 | 1217 error_noabort("undefined symbol '%s'", name); |
140 | 1218 } |
1219 } | |
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
|
1220 } else if (tccg_rdynamic && |
272 | 1221 ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
1222 /* if -rdynamic option, then export all non | |
1223 local symbols */ | |
1224 name = symtab_section->link->data + sym->st_name; | |
1225 put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | |
1226 sym->st_info, 0, | |
1227 sym->st_shndx, name); | |
140 | 1228 } |
1229 } | |
1230 | |
174 | 1231 if (s1->nb_errors) |
1232 goto fail; | |
1233 | |
140 | 1234 /* now look at unresolved dynamic symbols and export |
1235 corresponding symbol */ | |
174 | 1236 sym_end = (Elf32_Sym *)(s1->dynsymtab_section->data + |
1237 s1->dynsymtab_section->data_offset); | |
1238 for(esym = (Elf32_Sym *)s1->dynsymtab_section->data + 1; | |
140 | 1239 esym < sym_end; |
1240 esym++) { | |
1241 if (esym->st_shndx == SHN_UNDEF) { | |
174 | 1242 name = s1->dynsymtab_section->link->data + esym->st_name; |
140 | 1243 sym_index = find_elf_sym(symtab_section, name); |
1244 if (sym_index) { | |
272 | 1245 /* XXX: avoid adding a symbol if already |
1246 present because of -rdynamic ? */ | |
140 | 1247 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; |
174 | 1248 put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
140 | 1249 sym->st_info, 0, |
1250 sym->st_shndx, name); | |
1251 } else { | |
1252 if (ELF32_ST_BIND(esym->st_info) == STB_WEAK) { | |
1253 /* weak symbols can stay undefined */ | |
1254 } else { | |
1255 warning("undefined dynamic symbol '%s'", name); | |
1256 } | |
1257 } | |
1258 } | |
1259 } | |
1260 } else { | |
1261 int nb_syms; | |
1262 /* shared library case : we simply export all the global symbols */ | |
1263 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
|
1264 s1->symtab_to_dynsym = xzmalloc(sizeof(int) * nb_syms); |
140 | 1265 for(sym = (Elf32_Sym *)symtab_section->data + 1; |
1266 sym < sym_end; | |
1267 sym++) { | |
1268 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { | |
1269 name = symtab_section->link->data + sym->st_name; | |
174 | 1270 index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
140 | 1271 sym->st_info, 0, |
1272 sym->st_shndx, name); | |
174 | 1273 s1->symtab_to_dynsym[sym - |
1274 (Elf32_Sym *)symtab_section->data] = | |
140 | 1275 index; |
1276 } | |
1277 } | |
1278 } | |
1279 | |
174 | 1280 build_got_entries(s1); |
140 | 1281 |
1282 /* add a list of needed dlls */ | |
174 | 1283 for(i = 0; i < s1->nb_loaded_dlls; i++) { |
1284 DLLReference *dllref = s1->loaded_dlls[i]; | |
140 | 1285 if (dllref->level == 0) |
1286 put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); | |
1287 } | |
1288 /* XXX: currently, since we do not handle PIC code, we | |
1289 must relocate the readonly segments */ | |
1290 if (file_type == TCC_OUTPUT_DLL) | |
1291 put_dt(dynamic, DT_TEXTREL, 0); | |
1292 | |
1293 /* add necessary space for other entries */ | |
1294 saved_dynamic_data_offset = dynamic->data_offset; | |
1295 dynamic->data_offset += 8 * 9; | |
1296 } else { | |
1297 /* still need to build got entries in case of static link */ | |
174 | 1298 build_got_entries(s1); |
140 | 1299 } |
1300 } | |
1301 | |
1302 memset(&ehdr, 0, sizeof(ehdr)); | |
1303 | |
1304 /* we add a section for symbols */ | |
174 | 1305 strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
140 | 1306 put_elf_str(strsec, ""); |
1307 | |
1308 /* compute number of sections */ | |
174 | 1309 shnum = s1->nb_sections; |
140 | 1310 |
1311 /* 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
|
1312 section_order = xmalloc(sizeof(int) * shnum); |
140 | 1313 section_order[0] = 0; |
1314 sh_order_index = 1; | |
1315 | |
1316 /* compute number of program headers */ | |
1317 switch(file_type) { | |
1318 default: | |
1319 case TCC_OUTPUT_OBJ: | |
1320 phnum = 0; | |
1321 break; | |
1322 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
|
1323 if (!tccg_static_link) |
140 | 1324 phnum = 4; |
1325 else | |
1326 phnum = 2; | |
1327 break; | |
1328 case TCC_OUTPUT_DLL: | |
1329 phnum = 3; | |
1330 break; | |
1331 } | |
1332 | |
1333 /* allocate strings for section names and decide if an unallocated | |
1334 section should be output */ | |
1335 /* NOTE: the strsec section comes last, so its size is also | |
1336 correct ! */ | |
174 | 1337 for(i = 1; i < s1->nb_sections; i++) { |
1338 s = s1->sections[i]; | |
140 | 1339 s->sh_name = put_elf_str(strsec, s->name); |
1340 /* when generating a DLL, we include relocations but we may | |
1341 patch them */ | |
1342 if (file_type == TCC_OUTPUT_DLL && | |
1343 s->sh_type == SHT_REL && | |
1344 !(s->sh_flags & SHF_ALLOC)) { | |
174 | 1345 prepare_dynamic_rel(s1, s); |
140 | 1346 } else if (do_debug || |
1347 file_type == TCC_OUTPUT_OBJ || | |
1348 (s->sh_flags & SHF_ALLOC) || | |
174 | 1349 i == (s1->nb_sections - 1)) { |
140 | 1350 /* we output all sections if debug or object file */ |
1351 s->sh_size = s->data_offset; | |
1352 } | |
1353 } | |
1354 | |
1355 /* 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
|
1356 phdr = xzmalloc(phnum * sizeof(Elf32_Phdr)); |
140 | 1357 |
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
|
1358 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1359 file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); |
1360 } else { | |
1361 file_offset = 0; | |
1362 } | |
140 | 1363 if (phnum > 0) { |
1364 /* 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
|
1365 if (tccg_has_text_addr) { |
319 | 1366 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
|
1367 addr = tccg_text_addr; |
319 | 1368 /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
1369 ELF_PAGE_SIZE */ | |
1370 a_offset = addr & (ELF_PAGE_SIZE - 1); | |
1371 p_offset = file_offset & (ELF_PAGE_SIZE - 1); | |
1372 if (a_offset < p_offset) | |
1373 a_offset += ELF_PAGE_SIZE; | |
1374 file_offset += (a_offset - p_offset); | |
1375 } else { | |
1376 if (file_type == TCC_OUTPUT_DLL) | |
1377 addr = 0; | |
1378 else | |
1379 addr = ELF_START_ADDR; | |
1380 /* compute address after headers */ | |
1381 addr += (file_offset & (ELF_PAGE_SIZE - 1)); | |
1382 } | |
1383 | |
140 | 1384 /* dynamic relocation table information, for .dynamic section */ |
1385 rel_size = 0; | |
1386 rel_addr = 0; | |
1387 | |
1388 /* leave one program header for the program interpreter */ | |
1389 ph = &phdr[0]; | |
1390 if (interp) | |
1391 ph++; | |
1392 | |
1393 for(j = 0; j < 2; j++) { | |
1394 ph->p_type = PT_LOAD; | |
1395 if (j == 0) | |
1396 ph->p_flags = PF_R | PF_X; | |
1397 else | |
1398 ph->p_flags = PF_R | PF_W; | |
1399 ph->p_align = ELF_PAGE_SIZE; | |
1400 | |
1401 /* we do the following ordering: interp, symbol tables, | |
1402 relocations, progbits, nobits */ | |
1403 /* XXX: do faster and simpler sorting */ | |
1404 for(k = 0; k < 5; k++) { | |
174 | 1405 for(i = 1; i < s1->nb_sections; i++) { |
1406 s = s1->sections[i]; | |
140 | 1407 /* compute if section should be included */ |
1408 if (j == 0) { | |
1409 if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != | |
1410 SHF_ALLOC) | |
1411 continue; | |
1412 } else { | |
1413 if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != | |
1414 (SHF_ALLOC | SHF_WRITE)) | |
1415 continue; | |
1416 } | |
1417 if (s == interp) { | |
1418 if (k != 0) | |
1419 continue; | |
1420 } else if (s->sh_type == SHT_DYNSYM || | |
1421 s->sh_type == SHT_STRTAB || | |
1422 s->sh_type == SHT_HASH) { | |
1423 if (k != 1) | |
1424 continue; | |
1425 } else if (s->sh_type == SHT_REL) { | |
1426 if (k != 2) | |
1427 continue; | |
1428 } else if (s->sh_type == SHT_NOBITS) { | |
1429 if (k != 4) | |
1430 continue; | |
1431 } else { | |
1432 if (k != 3) | |
1433 continue; | |
1434 } | |
1435 section_order[sh_order_index++] = i; | |
1436 | |
1437 /* section matches: we align it and add its size */ | |
319 | 1438 tmp = addr; |
1439 addr = (addr + s->sh_addralign - 1) & | |
140 | 1440 ~(s->sh_addralign - 1); |
319 | 1441 file_offset += addr - tmp; |
140 | 1442 s->sh_offset = file_offset; |
1443 s->sh_addr = addr; | |
1444 | |
1445 /* update program header infos */ | |
1446 if (ph->p_offset == 0) { | |
1447 ph->p_offset = file_offset; | |
1448 ph->p_vaddr = addr; | |
1449 ph->p_paddr = ph->p_vaddr; | |
1450 } | |
1451 /* update dynamic relocation infos */ | |
1452 if (s->sh_type == SHT_REL) { | |
1453 if (rel_size == 0) | |
1454 rel_addr = addr; | |
1455 rel_size += s->sh_size; | |
1456 } | |
1457 addr += s->sh_size; | |
1458 if (s->sh_type != SHT_NOBITS) | |
1459 file_offset += s->sh_size; | |
1460 } | |
1461 } | |
1462 ph->p_filesz = file_offset - ph->p_offset; | |
1463 ph->p_memsz = addr - ph->p_vaddr; | |
1464 ph++; | |
325 | 1465 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
|
1466 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1467 /* if in the middle of a page, we duplicate the page in |
1468 memory so that one copy is RX and the other is RW */ | |
1469 if ((addr & (ELF_PAGE_SIZE - 1)) != 0) | |
1470 addr += ELF_PAGE_SIZE; | |
1471 } else { | |
1472 addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); | |
1473 file_offset = (file_offset + ELF_PAGE_SIZE - 1) & | |
1474 ~(ELF_PAGE_SIZE - 1); | |
1475 } | |
1476 } | |
140 | 1477 } |
1478 | |
1479 /* if interpreter, then add corresponing program header */ | |
1480 if (interp) { | |
1481 ph = &phdr[0]; | |
1482 | |
1483 ph->p_type = PT_INTERP; | |
1484 ph->p_offset = interp->sh_offset; | |
1485 ph->p_vaddr = interp->sh_addr; | |
1486 ph->p_paddr = ph->p_vaddr; | |
1487 ph->p_filesz = interp->sh_size; | |
1488 ph->p_memsz = interp->sh_size; | |
1489 ph->p_flags = PF_R; | |
1490 ph->p_align = interp->sh_addralign; | |
1491 } | |
1492 | |
1493 /* if dynamic section, then add corresponing program header */ | |
1494 if (dynamic) { | |
1495 Elf32_Sym *sym_end; | |
1496 | |
1497 ph = &phdr[phnum - 1]; | |
1498 | |
1499 ph->p_type = PT_DYNAMIC; | |
1500 ph->p_offset = dynamic->sh_offset; | |
1501 ph->p_vaddr = dynamic->sh_addr; | |
1502 ph->p_paddr = ph->p_vaddr; | |
1503 ph->p_filesz = dynamic->sh_size; | |
1504 ph->p_memsz = dynamic->sh_size; | |
1505 ph->p_flags = PF_R | PF_W; | |
1506 ph->p_align = dynamic->sh_addralign; | |
1507 | |
1508 /* put GOT dynamic section address */ | |
174 | 1509 put32(s1->got->data, dynamic->sh_addr); |
140 | 1510 |
228 | 1511 /* relocate the PLT */ |
1512 if (file_type == TCC_OUTPUT_EXE) { | |
1513 uint8_t *p, *p_end; | |
1514 | |
1515 p = s1->plt->data; | |
1516 p_end = p + s1->plt->data_offset; | |
255 | 1517 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
|
1518 #if defined(TINYCC_TARGET_I386) |
228 | 1519 put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
255 | 1520 put32(p + 8, get32(p + 8) + s1->got->sh_addr); |
228 | 1521 p += 16; |
255 | 1522 while (p < p_end) { |
1523 put32(p + 2, get32(p + 2) + s1->got->sh_addr); | |
1524 p += 16; | |
1525 } | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1526 #elif defined(TINYCC_TARGET_ARM) |
295 | 1527 int x; |
1528 x=s1->got->sh_addr - s1->plt->sh_addr - 12; | |
1529 p +=16; | |
1530 while (p < p_end) { | |
1531 put32(p + 12, x + get32(p + 12) + s1->plt->data - p); | |
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_C67) |
305 | 1535 /* XXX: TODO */ |
295 | 1536 #else |
1537 #error unsupported CPU | |
1538 #endif | |
228 | 1539 } |
1540 } | |
1541 | |
1542 /* relocate symbols in .dynsym */ | |
174 | 1543 sym_end = (Elf32_Sym *)(s1->dynsym->data + s1->dynsym->data_offset); |
1544 for(sym = (Elf32_Sym *)s1->dynsym->data + 1; | |
140 | 1545 sym < sym_end; |
1546 sym++) { | |
1547 if (sym->st_shndx == SHN_UNDEF) { | |
228 | 1548 /* relocate to the PLT if the symbol corresponds |
1549 to a PLT entry */ | |
1550 if (sym->st_value) | |
1551 sym->st_value += s1->plt->sh_addr; | |
140 | 1552 } else if (sym->st_shndx < SHN_LORESERVE) { |
1553 /* do symbol relocation */ | |
174 | 1554 sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
140 | 1555 } |
1556 } | |
228 | 1557 |
140 | 1558 /* put dynamic section entries */ |
1559 dynamic->data_offset = saved_dynamic_data_offset; | |
174 | 1560 put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
140 | 1561 put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); |
174 | 1562 put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
140 | 1563 put_dt(dynamic, DT_STRSZ, dynstr->data_offset); |
1564 put_dt(dynamic, DT_SYMENT, sizeof(Elf32_Sym)); | |
1565 put_dt(dynamic, DT_REL, rel_addr); | |
1566 put_dt(dynamic, DT_RELSZ, rel_size); | |
1567 put_dt(dynamic, DT_RELENT, sizeof(Elf32_Rel)); | |
1568 put_dt(dynamic, DT_NULL, 0); | |
1569 } | |
1570 | |
1571 ehdr.e_phentsize = sizeof(Elf32_Phdr); | |
1572 ehdr.e_phnum = phnum; | |
1573 ehdr.e_phoff = sizeof(Elf32_Ehdr); | |
1574 } | |
1575 | |
1576 /* all other sections come after */ | |
174 | 1577 for(i = 1; i < s1->nb_sections; i++) { |
1578 s = s1->sections[i]; | |
140 | 1579 if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
1580 continue; | |
1581 section_order[sh_order_index++] = i; | |
1582 | |
1583 file_offset = (file_offset + s->sh_addralign - 1) & | |
1584 ~(s->sh_addralign - 1); | |
1585 s->sh_offset = file_offset; | |
1586 if (s->sh_type != SHT_NOBITS) | |
1587 file_offset += s->sh_size; | |
1588 } | |
1589 | |
1590 /* if building executable or DLL, then relocate each section | |
1591 except the GOT which is already relocated */ | |
1592 if (file_type != TCC_OUTPUT_OBJ) { | |
174 | 1593 relocate_syms(s1, 0); |
1594 | |
1595 if (s1->nb_errors != 0) { | |
1596 fail: | |
1597 ret = -1; | |
1598 goto the_end; | |
1599 } | |
140 | 1600 |
1601 /* relocate sections */ | |
1602 /* XXX: ignore sections with allocated relocations ? */ | |
174 | 1603 for(i = 1; i < s1->nb_sections; i++) { |
1604 s = s1->sections[i]; | |
1605 if (s->reloc && s != s1->got) | |
140 | 1606 relocate_section(s1, s); |
1607 } | |
1608 | |
1609 /* relocate relocation entries if the relocation tables are | |
1610 allocated in the executable */ | |
174 | 1611 for(i = 1; i < s1->nb_sections; i++) { |
1612 s = s1->sections[i]; | |
140 | 1613 if ((s->sh_flags & SHF_ALLOC) && |
1614 s->sh_type == SHT_REL) { | |
174 | 1615 relocate_rel(s1, s); |
140 | 1616 } |
1617 } | |
1618 | |
1619 /* get entry point address */ | |
1620 if (file_type == TCC_OUTPUT_EXE) | |
283 | 1621 ehdr.e_entry = (unsigned long)tcc_get_symbol_err(s1, "_start"); |
140 | 1622 else |
1623 ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ | |
1624 } | |
1625 | |
1626 /* write elf file */ | |
1627 if (file_type == TCC_OUTPUT_OBJ) | |
1628 mode = 0666; | |
1629 else | |
1630 mode = 0777; | |
325 | 1631 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
174 | 1632 if (fd < 0) { |
1633 error_noabort("could not write '%s'", filename); | |
1634 goto fail; | |
1635 } | |
325 | 1636 f = fdopen(fd, "wb"); |
1637 | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1638 #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
|
1639 if (tccg_output_format == TCC_OUTPUT_FORMAT_COFF) { |
325 | 1640 tcc_output_coff(s1, f); |
1641 } else | |
1642 #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
|
1643 if (tccg_output_format == TCC_OUTPUT_FORMAT_ELF) { |
325 | 1644 sort_syms(s1, symtab_section); |
1645 | |
1646 /* align to 4 */ | |
1647 file_offset = (file_offset + 3) & -4; | |
1648 | |
1649 /* fill header */ | |
1650 ehdr.e_ident[0] = ELFMAG0; | |
1651 ehdr.e_ident[1] = ELFMAG1; | |
1652 ehdr.e_ident[2] = ELFMAG2; | |
1653 ehdr.e_ident[3] = ELFMAG3; | |
1654 ehdr.e_ident[4] = ELFCLASS32; | |
1655 ehdr.e_ident[5] = ELFDATA2LSB; | |
1656 ehdr.e_ident[6] = EV_CURRENT; | |
1657 #ifdef __FreeBSD__ | |
1658 ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; | |
1659 #endif | |
555
646f1f0972b6
Update TCC_TARGET_* to TINYCC_TARGET_* (which is what new build sets).
Rob Landley <rob@landley.net>
parents:
554
diff
changeset
|
1660 #ifdef TINYCC_TARGET_ARM |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1661 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1662 ehdr.e_ident[EI_OSABI] = 0; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1663 ehdr.e_flags = 4 << 24; |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1664 #else |
325 | 1665 ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
1666 #endif | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1667 #endif |
325 | 1668 switch(file_type) { |
1669 default: | |
1670 case TCC_OUTPUT_EXE: | |
1671 ehdr.e_type = ET_EXEC; | |
1672 break; | |
1673 case TCC_OUTPUT_DLL: | |
1674 ehdr.e_type = ET_DYN; | |
1675 break; | |
1676 case TCC_OUTPUT_OBJ: | |
1677 ehdr.e_type = ET_REL; | |
1678 break; | |
140 | 1679 } |
325 | 1680 ehdr.e_machine = EM_TCC_TARGET; |
1681 ehdr.e_version = EV_CURRENT; | |
1682 ehdr.e_shoff = file_offset; | |
1683 ehdr.e_ehsize = sizeof(Elf32_Ehdr); | |
1684 ehdr.e_shentsize = sizeof(Elf32_Shdr); | |
1685 ehdr.e_shnum = shnum; | |
1686 ehdr.e_shstrndx = shnum - 1; | |
1687 | |
1688 fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f); | |
1689 fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f); | |
1690 offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr); | |
1691 | |
1692 for(i=1;i<s1->nb_sections;i++) { | |
1693 s = s1->sections[section_order[i]]; | |
1694 if (s->sh_type != SHT_NOBITS) { | |
1695 while (offset < s->sh_offset) { | |
1696 fputc(0, f); | |
1697 offset++; | |
1698 } | |
1699 size = s->sh_size; | |
1700 fwrite(s->data, 1, size, f); | |
1701 offset += size; | |
1702 } | |
1703 } | |
1704 | |
1705 /* output section headers */ | |
1706 while (offset < ehdr.e_shoff) { | |
1707 fputc(0, f); | |
1708 offset++; | |
1709 } | |
140 | 1710 |
325 | 1711 for(i=0;i<s1->nb_sections;i++) { |
1712 sh = &shdr; | |
1713 memset(sh, 0, sizeof(Elf32_Shdr)); | |
1714 s = s1->sections[i]; | |
1715 if (s) { | |
1716 sh->sh_name = s->sh_name; | |
1717 sh->sh_type = s->sh_type; | |
1718 sh->sh_flags = s->sh_flags; | |
1719 sh->sh_entsize = s->sh_entsize; | |
1720 sh->sh_info = s->sh_info; | |
1721 if (s->link) | |
1722 sh->sh_link = s->link->sh_num; | |
1723 sh->sh_addralign = s->sh_addralign; | |
1724 sh->sh_addr = s->sh_addr; | |
1725 sh->sh_offset = s->sh_offset; | |
1726 sh->sh_size = s->sh_size; | |
1727 } | |
1728 fwrite(sh, 1, sizeof(Elf32_Shdr), f); | |
140 | 1729 } |
325 | 1730 } else { |
1731 tcc_output_binary(s1, f, section_order); | |
140 | 1732 } |
1733 fclose(f); | |
1734 | |
174 | 1735 ret = 0; |
1736 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
|
1737 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
|
1738 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
|
1739 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
|
1740 free(s1->got_offsets); |
174 | 1741 return ret; |
140 | 1742 } |
1743 | |
1744 static void *load_data(int fd, unsigned long file_offset, unsigned long size) | |
1745 { | |
1746 void *data; | |
1747 | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
1748 data = xmalloc(size); |
140 | 1749 lseek(fd, file_offset, SEEK_SET); |
1750 read(fd, data, size); | |
1751 return data; | |
1752 } | |
1753 | |
1754 typedef struct SectionMergeInfo { | |
1755 Section *s; /* corresponding existing section */ | |
1756 unsigned long offset; /* offset of the new section in the existing section */ | |
287 | 1757 uint8_t new_section; /* true if section 's' was added */ |
1758 uint8_t link_once; /* true if link once section */ | |
140 | 1759 } SectionMergeInfo; |
1760 | |
1761 /* load an object file and merge it with current files */ | |
1762 /* XXX: handle correctly stab (debug) info */ | |
1763 static int tcc_load_object_file(TCCState *s1, | |
1764 int fd, unsigned long file_offset) | |
1765 { | |
1766 Elf32_Ehdr ehdr; | |
1767 Elf32_Shdr *shdr, *sh; | |
174 | 1768 int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
140 | 1769 unsigned char *strsec, *strtab; |
1770 int *old_to_new_syms; | |
1771 char *sh_name, *name; | |
1772 SectionMergeInfo *sm_table, *sm; | |
1773 Elf32_Sym *sym, *symtab; | |
1774 Elf32_Rel *rel, *rel_end; | |
1775 Section *s; | |
1776 | |
1777 if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) | |
174 | 1778 goto fail1; |
140 | 1779 if (ehdr.e_ident[0] != ELFMAG0 || |
1780 ehdr.e_ident[1] != ELFMAG1 || | |
1781 ehdr.e_ident[2] != ELFMAG2 || | |
1782 ehdr.e_ident[3] != ELFMAG3) | |
174 | 1783 goto fail1; |
140 | 1784 /* test if object file */ |
1785 if (ehdr.e_type != ET_REL) | |
174 | 1786 goto fail1; |
140 | 1787 /* test CPU specific stuff */ |
1788 if (ehdr.e_ident[5] != ELFDATA2LSB || | |
295 | 1789 ehdr.e_machine != EM_TCC_TARGET) { |
174 | 1790 fail1: |
1791 error_noabort("invalid object file"); | |
1792 return -1; | |
140 | 1793 } |
1794 /* read sections */ | |
1795 shdr = load_data(fd, file_offset + ehdr.e_shoff, | |
1796 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
|
1797 sm_table = xzmalloc(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
140 | 1798 |
1799 /* load section names */ | |
1800 sh = &shdr[ehdr.e_shstrndx]; | |
1801 strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1802 | |
1803 /* load symtab and strtab */ | |
174 | 1804 old_to_new_syms = NULL; |
140 | 1805 symtab = NULL; |
1806 strtab = NULL; | |
1807 nb_syms = 0; | |
1808 for(i = 1; i < ehdr.e_shnum; i++) { | |
1809 sh = &shdr[i]; | |
1810 if (sh->sh_type == SHT_SYMTAB) { | |
174 | 1811 if (symtab) { |
1812 error_noabort("object must contain only one symtab"); | |
1813 fail: | |
1814 ret = -1; | |
1815 goto the_end; | |
1816 } | |
140 | 1817 nb_syms = sh->sh_size / sizeof(Elf32_Sym); |
1818 symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1819 sm_table[i].s = symtab_section; | |
1820 | |
1821 /* now load strtab */ | |
1822 sh = &shdr[sh->sh_link]; | |
1823 strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); | |
1824 } | |
1825 } | |
1826 | |
1827 /* now examine each section and try to merge its content with the | |
1828 ones in memory */ | |
1829 for(i = 1; i < ehdr.e_shnum; i++) { | |
1830 /* no need to examine section name strtab */ | |
1831 if (i == ehdr.e_shstrndx) | |
1832 continue; | |
1833 sh = &shdr[i]; | |
1834 sh_name = strsec + sh->sh_name; | |
1835 /* ignore sections types we do not handle */ | |
1836 if (sh->sh_type != SHT_PROGBITS && | |
1837 sh->sh_type != SHT_REL && | |
409
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1838 #ifdef TCC_ARM_EABI |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1839 sh->sh_type != SHT_ARM_EXIDX && |
41f19a7b4093
Support for ARM EABI, by Daniel Glockner.
landley@driftwood
parents:
396
diff
changeset
|
1840 #endif |
140 | 1841 sh->sh_type != SHT_NOBITS) |
1842 continue; | |
1843 if (sh->sh_addralign < 1) | |
1844 sh->sh_addralign = 1; | |
1845 /* find corresponding section, if any */ | |
174 | 1846 for(j = 1; j < s1->nb_sections;j++) { |
1847 s = s1->sections[j]; | |
287 | 1848 if (!strcmp(s->name, sh_name)) { |
1849 if (!strncmp(sh_name, ".gnu.linkonce", | |
1850 sizeof(".gnu.linkonce") - 1)) { | |
1851 /* if a 'linkonce' section is already present, we | |
1852 do not add it again. It is a little tricky as | |
1853 symbols can still be defined in | |
1854 it. */ | |
1855 sm_table[i].link_once = 1; | |
1856 goto next; | |
1857 } else { | |
1858 goto found; | |
1859 } | |
1860 } | |
140 | 1861 } |
1862 /* not found: create new section */ | |
174 | 1863 s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags); |
140 | 1864 /* take as much info as possible from the section. sh_link and |
1865 sh_info will be updated later */ | |
1866 s->sh_addralign = sh->sh_addralign; | |
1867 s->sh_entsize = sh->sh_entsize; | |
1868 sm_table[i].new_section = 1; | |
1869 found: | |
174 | 1870 if (sh->sh_type != s->sh_type) { |
1871 error_noabort("invalid section type"); | |
140 | 1872 goto fail; |
174 | 1873 } |
140 | 1874 |
1875 /* align start of section */ | |
1876 offset = s->data_offset; | |
1877 size = sh->sh_addralign - 1; | |
1878 offset = (offset + size) & ~size; | |
1879 if (sh->sh_addralign > s->sh_addralign) | |
1880 s->sh_addralign = sh->sh_addralign; | |
1881 s->data_offset = offset; | |
1882 sm_table[i].offset = offset; | |
1883 sm_table[i].s = s; | |
1884 /* concatenate sections */ | |
1885 size = sh->sh_size; | |
1886 if (sh->sh_type != SHT_NOBITS) { | |
1887 unsigned char *ptr; | |
1888 lseek(fd, file_offset + sh->sh_offset, SEEK_SET); | |
151 | 1889 ptr = section_ptr_add(s, size); |
140 | 1890 read(fd, ptr, size); |
151 | 1891 } else { |
1892 s->data_offset += size; | |
140 | 1893 } |
287 | 1894 next: ; |
140 | 1895 } |
1896 | |
1897 /* second short pass to update sh_link and sh_info fields of new | |
1898 sections */ | |
1899 for(i = 1; i < ehdr.e_shnum; i++) { | |
1900 s = sm_table[i].s; | |
1901 if (!s || !sm_table[i].new_section) | |
1902 continue; | |
1903 sh = &shdr[i]; | |
1904 if (sh->sh_link > 0) | |
1905 s->link = sm_table[sh->sh_link].s; | |
1906 if (sh->sh_type == SHT_REL) { | |
1907 s->sh_info = sm_table[sh->sh_info].s->sh_num; | |
1908 /* update backward link */ | |
174 | 1909 s1->sections[s->sh_info]->reloc = s; |
140 | 1910 } |
1911 } | |
396
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1912 sm = sm_table; |
140 | 1913 |
1914 /* 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
|
1915 old_to_new_syms = xzmalloc(nb_syms * sizeof(int)); |
140 | 1916 |
1917 sym = symtab + 1; | |
1918 for(i = 1; i < nb_syms; i++, sym++) { | |
1919 if (sym->st_shndx != SHN_UNDEF && | |
1920 sym->st_shndx < SHN_LORESERVE) { | |
1921 sm = &sm_table[sym->st_shndx]; | |
287 | 1922 if (sm->link_once) { |
1923 /* if a symbol is in a link once section, we use the | |
1924 already defined symbol. It is very important to get | |
1925 correct relocations */ | |
1926 if (ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { | |
1927 name = strtab + sym->st_name; | |
1928 sym_index = find_elf_sym(symtab_section, name); | |
1929 if (sym_index) | |
1930 old_to_new_syms[i] = sym_index; | |
1931 } | |
1932 continue; | |
1933 } | |
140 | 1934 /* if no corresponding section added, no need to add symbol */ |
1935 if (!sm->s) | |
1936 continue; | |
1937 /* convert section number */ | |
1938 sym->st_shndx = sm->s->sh_num; | |
1939 /* offset value */ | |
1940 sym->st_value += sm->offset; | |
1941 } | |
1942 /* add symbol */ | |
1943 name = strtab + sym->st_name; | |
1944 sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, | |
356 | 1945 sym->st_info, sym->st_other, |
1946 sym->st_shndx, name); | |
140 | 1947 old_to_new_syms[i] = sym_index; |
1948 } | |
1949 | |
1950 /* third pass to patch relocation entries */ | |
1951 for(i = 1; i < ehdr.e_shnum; i++) { | |
1952 s = sm_table[i].s; | |
1953 if (!s) | |
1954 continue; | |
1955 sh = &shdr[i]; | |
1956 offset = sm_table[i].offset; | |
1957 switch(s->sh_type) { | |
1958 case SHT_REL: | |
1959 /* take relocation offset information */ | |
1960 offseti = sm_table[sh->sh_info].offset; | |
1961 rel_end = (Elf32_Rel *)(s->data + s->data_offset); | |
1962 for(rel = (Elf32_Rel *)(s->data + offset); | |
1963 rel < rel_end; | |
1964 rel++) { | |
1965 int type; | |
1966 unsigned sym_index; | |
1967 /* convert symbol index */ | |
1968 type = ELF32_R_TYPE(rel->r_info); | |
1969 sym_index = ELF32_R_SYM(rel->r_info); | |
1970 /* NOTE: only one symtab assumed */ | |
1971 if (sym_index >= nb_syms) | |
1972 goto invalid_reloc; | |
1973 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
|
1974 /* ignore link_once in rel section. */ |
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1975 if (!sym_index && !sm->link_once) { |
140 | 1976 invalid_reloc: |
396
928147ea8ab6
Fix "invalid relocation entry" problem on ubuntu. Fix from Bernhard
landley@driftwood
parents:
394
diff
changeset
|
1977 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
|
1978 i, strsec + sh->sh_name, rel->r_offset); |
174 | 1979 goto fail; |
140 | 1980 } |
1981 rel->r_info = ELF32_R_INFO(sym_index, type); | |
1982 /* offset the relocation offset */ | |
1983 rel->r_offset += offseti; | |
1984 } | |
1985 break; | |
1986 default: | |
1987 break; | |
1988 } | |
1989 } | |
174 | 1990 |
1991 ret = 0; | |
1992 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
|
1993 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
|
1994 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
|
1995 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
|
1996 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
|
1997 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
|
1998 free(shdr); |
174 | 1999 return ret; |
140 | 2000 } |
2001 | |
2002 #define ARMAG "!<arch>\012" /* For COFF and a.out archives */ | |
2003 | |
2004 typedef struct ArchiveHeader { | |
2005 char ar_name[16]; /* name of this member */ | |
2006 char ar_date[12]; /* file mtime */ | |
2007 char ar_uid[6]; /* owner uid; printed as decimal */ | |
2008 char ar_gid[6]; /* owner gid; printed as decimal */ | |
2009 char ar_mode[8]; /* file mode, printed as octal */ | |
2010 char ar_size[10]; /* file size, printed as decimal */ | |
2011 char ar_fmag[2]; /* should contain ARFMAG */ | |
2012 } ArchiveHeader; | |
2013 | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2014 static int get_be32(uint8_t *b) |
259 | 2015 { |
2016 return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); | |
2017 } | |
2018 | |
2019 /* load only the objects which resolve undefined symbols */ | |
2020 static int tcc_load_alacarte(TCCState *s1, int fd, int size) | |
2021 { | |
2022 int i, bound, nsyms, sym_index, off, ret; | |
2023 uint8_t *data; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2024 char *ar_names, *p; |
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2025 uint8_t *ar_index; |
259 | 2026 Elf32_Sym *sym; |
2027 | |
507
67453c7d623e
Clean up malloc() and friends to xmalloc/xzmalloc/xstrdup, and remove redundant
Rob Landley <rob@landley.net>
parents:
505
diff
changeset
|
2028 data = xmalloc(size); |
259 | 2029 if (read(fd, data, size) != size) |
2030 goto fail; | |
2031 nsyms = get_be32(data); | |
2032 ar_index = data + 4; | |
2033 ar_names = ar_index + nsyms * 4; | |
2034 | |
2035 do { | |
2036 bound = 0; | |
2037 for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { | |
2038 sym_index = find_elf_sym(symtab_section, p); | |
2039 if(sym_index) { | |
2040 sym = &((Elf32_Sym *)symtab_section->data)[sym_index]; | |
2041 if(sym->st_shndx == SHN_UNDEF) { | |
2042 off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); | |
2043 #if 0 | |
2044 printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); | |
2045 #endif | |
2046 ++bound; | |
2047 lseek(fd, off, SEEK_SET); | |
2048 if(tcc_load_object_file(s1, fd, off) < 0) { | |
2049 fail: | |
2050 ret = -1; | |
2051 goto the_end; | |
2052 } | |
2053 } | |
2054 } | |
2055 } | |
2056 } while(bound); | |
2057 ret = 0; | |
2058 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
|
2059 free(data); |
259 | 2060 return ret; |
2061 } | |
2062 | |
140 | 2063 /* load a '.a' file */ |
2064 static int tcc_load_archive(TCCState *s1, int fd) | |
2065 { | |
2066 ArchiveHeader hdr; | |
2067 char ar_size[11]; | |
2068 char ar_name[17]; | |
2069 char magic[8]; | |
2070 int size, len, i; | |
2071 unsigned long file_offset; | |
2072 | |
2073 /* skip magic which was already checked */ | |
2074 read(fd, magic, sizeof(magic)); | |
2075 | |
2076 for(;;) { | |
2077 len = read(fd, &hdr, sizeof(hdr)); | |
2078 if (len == 0) | |
2079 break; | |
174 | 2080 if (len != sizeof(hdr)) { |
2081 error_noabort("invalid archive"); | |
2082 return -1; | |
2083 } | |
140 | 2084 memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
2085 ar_size[sizeof(hdr.ar_size)] = '\0'; | |
2086 size = strtol(ar_size, NULL, 0); | |
2087 memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name)); | |
2088 for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { | |
2089 if (ar_name[i] != ' ') | |
2090 break; | |
2091 } | |
2092 ar_name[i + 1] = '\0'; | |
2093 // printf("name='%s' size=%d %s\n", ar_name, size, ar_size); | |
2094 file_offset = lseek(fd, 0, SEEK_CUR); | |
259 | 2095 /* align to even */ |
2096 size = (size + 1) & ~1; | |
2097 if (!strcmp(ar_name, "/")) { | |
2098 /* coff symbol table : we handle it */ | |
2099 if(s1->alacarte_link) | |
2100 return tcc_load_alacarte(s1, fd, size); | |
2101 } else if (!strcmp(ar_name, "//") || | |
2102 !strcmp(ar_name, "__.SYMDEF") || | |
2103 !strcmp(ar_name, "__.SYMDEF/") || | |
2104 !strcmp(ar_name, "ARFILENAMES/")) { | |
140 | 2105 /* skip symbol table or archive names */ |
2106 } else { | |
174 | 2107 if (tcc_load_object_file(s1, fd, file_offset) < 0) |
2108 return -1; | |
140 | 2109 } |
2110 lseek(fd, file_offset + size, SEEK_SET); | |
2111 } | |
2112 return 0; | |
2113 } | |
2114 | |
2115 /* load a DLL and all referenced DLLs. 'level = 0' means that the DLL | |
2116 is referenced by the user (so it should be added as DT_NEEDED in | |
2117 the generated ELF file) */ | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2118 static int tcc_load_dll(TCCState *s1, int fd, char *filename, int level) |
140 | 2119 { |
2120 Elf32_Ehdr ehdr; | |
2121 Elf32_Shdr *shdr, *sh, *sh1; | |
394 | 2122 int i, j, nb_syms, nb_dts, sym_bind, ret; |
140 | 2123 Elf32_Sym *sym, *dynsym; |
2124 Elf32_Dyn *dt, *dynamic; | |
2125 unsigned char *dynstr; | |
553
4533aa54ffcf
More simplification and attacking warnings.
Rob Landley <rob@landley.net>
parents:
547
diff
changeset
|
2126 char *name, *soname, *p; |
140 | 2127 DLLReference *dllref; |
2128 | |
2129 read(fd, &ehdr, sizeof(ehdr)); | |
2130 | |
2131 /* test CPU specific stuff */ | |
2132 if (ehdr.e_ident[5] != ELFDATA2LSB || | |
295 | 2133 ehdr.e_machine != EM_TCC_TARGET) { |
174 | 2134 error_noabort("bad architecture"); |
2135 return -1; | |
2136 } | |
140 | 2137 |
2138 /* read sections */ | |
2139 shdr = load_data(fd, ehdr.e_shoff, sizeof(Elf32_Shdr) * ehdr.e_shnum); | |
2140 | |
2141 /* load dynamic section and dynamic symbols */ | |
2142 nb_syms = 0; | |
2143 nb_dts = 0; | |
2144 dynamic = NULL; | |
2145 dynsym = NULL; /* avoid warning */ | |
2146 dynstr = NULL; /* avoid warning */ | |
2147 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { | |
2148 switch(sh->sh_type) { | |
2149 case SHT_DYNAMIC: | |
2150 nb_dts = sh->sh_size / sizeof(Elf32_Dyn); | |
2151 dynamic = load_data(fd, sh->sh_offset, sh->sh_size); | |
2152 break; | |
2153 case SHT_DYNSYM: | |
2154 nb_syms = sh->sh_size / sizeof(Elf32_Sym); | |
2155 dynsym = load_data(fd, sh->sh_offset, sh->sh_size); | |
2156 sh1 = &shdr[sh->sh_link]; | |
2157 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); | |
2158 break; | |
2159 default: | |
2160 break; | |
2161 } | |
2162 } | |
2163 | |
2164 /* compute the real library name */ | |
2165 soname = filename; | |
2166 p = strrchr(soname, '/'); | |
2167 if (p) | |
2168 soname = p + 1; | |
2169 | |
2170 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { | |
2171 if (dt->d_tag == DT_SONAME) { | |
2172 soname = dynstr + dt->d_un.d_val; | |
2173 } | |
2174 } | |
2175 | |
2176 /* if the dll is already loaded, do not load it */ | |
174 | 2177 for(i = 0; i < s1->nb_loaded_dlls; i++) { |
2178 dllref = s1->loaded_dlls[i]; | |
140 | 2179 if (!strcmp(soname, dllref->name)) { |
2180 /* but update level if needed */ | |
2181 if (level < dllref->level) | |
2182 dllref->level = level; | |
174 | 2183 ret = 0; |
140 | 2184 goto the_end; |
2185 } | |
2186 } | |
2187 | |
2188 // printf("loading dll '%s'\n", soname); | |
2189 | |
2190 /* 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
|
2191 dllref = xmalloc(sizeof(DLLReference) + strlen(soname)); |
140 | 2192 dllref->level = level; |
2193 strcpy(dllref->name, soname); | |
174 | 2194 dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
140 | 2195 |
2196 /* add dynamic symbols in dynsym_section */ | |
2197 for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { | |
2198 sym_bind = ELF32_ST_BIND(sym->st_info); | |
2199 if (sym_bind == STB_LOCAL) | |
2200 continue; | |
2201 name = dynstr + sym->st_name; | |
174 | 2202 add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
372 | 2203 sym->st_info, sym->st_other, sym->st_shndx, name); |
140 | 2204 } |
2205 | |
2206 /* load all referenced DLLs */ | |
2207 for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { | |
2208 switch(dt->d_tag) { | |
2209 case DT_NEEDED: | |
2210 name = dynstr + dt->d_un.d_val; | |
394 | 2211 for(j = 0; j < s1->nb_loaded_dlls; j++) { |
2212 dllref = s1->loaded_dlls[j]; | |
140 | 2213 if (!strcmp(name, dllref->name)) |
2214 goto already_loaded; | |
2215 } | |
174 | 2216 if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
2217 error_noabort("referenced dll '%s' not found", name); | |
2218 ret = -1; | |
2219 goto the_end; | |
2220 } | |
140 | 2221 already_loaded: |
2222 break; | |
2223 } | |
2224 } | |
174 | 2225 ret = 0; |
140 | 2226 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
|
2227 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
|
2228 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
|
2229 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
|
2230 free(shdr); |
174 | 2231 return ret; |
140 | 2232 } |
2233 | |
191 | 2234 #define LD_TOK_NAME 256 |
2235 #define LD_TOK_EOF (-1) | |
2236 | |
2237 /* return next ld script token */ | |
2238 static int ld_next(TCCState *s1, char *name, int name_size) | |
140 | 2239 { |
191 | 2240 int c; |
140 | 2241 char *q; |
2242 | |
191 | 2243 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
|
2244 switch(fch) { |
191 | 2245 case ' ': |
2246 case '\t': | |
2247 case '\f': | |
2248 case '\v': | |
2249 case '\r': | |
2250 case '\n': | |
2251 inp(); | |
2252 goto redo; | |
2253 case '/': | |
2254 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
|
2255 if (fch == '*') { |
230 | 2256 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
|
2257 fch = file->buf_ptr[0]; |
191 | 2258 goto redo; |
2259 } else { | |
2260 q = name; | |
2261 *q++ = '/'; | |
2262 goto parse_name; | |
2263 } | |
2264 break; | |
2265 case 'a' ... 'z': | |
2266 case 'A' ... 'Z': | |
2267 case '_': | |
2268 case '\\': | |
2269 case '.': | |
2270 case '$': | |
2271 case '~': | |
2272 q = name; | |
2273 parse_name: | |
2274 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
|
2275 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
|
2276 (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
|
2277 (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
|
2278 strchr("/.-_+=$:\\,~", fch))) |
191 | 2279 break; |
2280 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
|
2281 *q++ = fch; |
191 | 2282 } |
2283 minp(); | |
2284 } | |
2285 *q = '\0'; | |
2286 c = LD_TOK_NAME; | |
2287 break; | |
2288 case CH_EOF: | |
2289 c = LD_TOK_EOF; | |
2290 break; | |
2291 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
|
2292 c = fch; |
191 | 2293 inp(); |
2294 break; | |
140 | 2295 } |
191 | 2296 #if 0 |
2297 printf("tok=%c %d\n", c, c); | |
2298 if (c == LD_TOK_NAME) | |
2299 printf(" name=%s\n", name); | |
2300 #endif | |
2301 return c; | |
140 | 2302 } |
191 | 2303 |
383 | 2304 static int ld_add_file_list(TCCState *s1, int as_needed) |
2305 { | |
2306 char filename[1024]; | |
2307 int t, ret; | |
2308 | |
2309 t = ld_next(s1, filename, sizeof(filename)); | |
2310 if (t != '(') | |
2311 expect("("); | |
2312 t = ld_next(s1, filename, sizeof(filename)); | |
2313 for(;;) { | |
2314 if (t == LD_TOK_EOF) { | |
2315 error_noabort("unexpected end of file"); | |
2316 return -1; | |
2317 } else if (t == ')') { | |
2318 break; | |
2319 } else if (t != LD_TOK_NAME) { | |
2320 error_noabort("filename expected"); | |
2321 return -1; | |
2322 } | |
2323 if (!strcmp(filename, "AS_NEEDED")) { | |
2324 ret = ld_add_file_list(s1, 1); | |
2325 if (ret) | |
2326 return ret; | |
2327 } else { | |
2328 /* 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
|
2329 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
|
2330 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
|
2331 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
|
2332 } |
383 | 2333 } |
2334 t = ld_next(s1, filename, sizeof(filename)); | |
2335 if (t == ',') { | |
2336 t = ld_next(s1, filename, sizeof(filename)); | |
2337 } | |
2338 } | |
2339 return 0; | |
2340 } | |
2341 | |
140 | 2342 /* interpret a subset of GNU ldscripts to handle the dummy libc.so |
2343 files */ | |
2344 static int tcc_load_ldscript(TCCState *s1) | |
2345 { | |
2346 char cmd[64]; | |
2347 char filename[1024]; | |
383 | 2348 int t, ret; |
140 | 2349 |
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
|
2350 //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
|
2351 fch = handle_eob(); |
140 | 2352 for(;;) { |
191 | 2353 t = ld_next(s1, cmd, sizeof(cmd)); |
2354 if (t == LD_TOK_EOF) | |
140 | 2355 return 0; |
191 | 2356 else if (t != LD_TOK_NAME) |
140 | 2357 return -1; |
2358 if (!strcmp(cmd, "INPUT") || | |
2359 !strcmp(cmd, "GROUP")) { | |
383 | 2360 ret = ld_add_file_list(s1, 0); |
2361 if (ret) | |
2362 return ret; | |
248 | 2363 } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
2364 !strcmp(cmd, "TARGET")) { | |
2365 /* ignore some commands */ | |
2366 t = ld_next(s1, cmd, sizeof(cmd)); | |
2367 if (t != '(') | |
2368 expect("("); | |
2369 for(;;) { | |
2370 t = ld_next(s1, filename, sizeof(filename)); | |
2371 if (t == LD_TOK_EOF) { | |
2372 error_noabort("unexpected end of file"); | |
2373 return -1; | |
2374 } else if (t == ')') { | |
2375 break; | |
2376 } | |
2377 } | |
140 | 2378 } else { |
2379 return -1; | |
2380 } | |
2381 } | |
2382 return 0; | |
2383 } |