Merge lp:~lqs/ubuntu/precise/tcc/tcc-fix-mmap-leak into lp:ubuntu/precise/tcc
- Precise (12.04)
- tcc-fix-mmap-leak
- Merge into precise
Proposed by
Qishuai Liu
Status: | Work in progress |
---|---|
Proposed branch: | lp:~lqs/ubuntu/precise/tcc/tcc-fix-mmap-leak |
Merge into: | lp:ubuntu/precise/tcc |
Diff against target: | 34400 lines |
To merge this branch: | bzr merge lp:~lqs/ubuntu/precise/tcc/tcc-fix-mmap-leak |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Needs Fixing | ||
Ubuntu branches | Pending | ||
Review via email: mp+134058@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 26. By Qishuai Liu
-
Fix mmap leak when mprotect() on an existing malloc`ed area.
- 25. By Thomas Preud'homme
-
[Paul Tagliamonte]
* Uploading Tom's fixes on his behalf. Although he's signed this upload
(he issued a debdiff), I've prepared this upload. Fix verified on
i386.[Thomas Preud'homme]
* debian/patches:
+ Fix incorrect reading of long long values on architecture with 32bits
registers like i386 and armel (Closes: #681281). - 24. By Thomas Preud'homme
-
* debian/patches:
+ Cherry-pick patch fixing incorrect shift result type (Closes: #679123).
* debian/control:
+ Update Vcs-Browser URL. - 23. By Thomas Preud'homme
-
* debian/patches:
+ Disable the new callsave_test test on arm since it uses alloca which is
not supported on arm (yet).
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.gitignore' |
2 | --- .gitignore 2012-03-06 00:19:03 +0000 |
3 | +++ .gitignore 2012-11-13 09:46:40 +0000 |
4 | @@ -30,11 +30,20 @@ |
5 | p2.c |
6 | tcctest[1234] |
7 | test[1234].out |
8 | +tests/tcclib.h |
9 | +tests/tcctest.gcc |
10 | .gdb_history |
11 | tcc.1 |
12 | tcc.pod |
13 | config.h |
14 | config.mak |
15 | config.texi |
16 | -tests |
17 | tags |
18 | +.DS_Store |
19 | +*.swp |
20 | +lib/x86_64 |
21 | +lib/i386 |
22 | +tcc-doc.info |
23 | +conftest* |
24 | +tiny_libmaker |
25 | +*.dSYM |
26 | |
27 | === added file '.pc/.quilt_patches' |
28 | --- .pc/.quilt_patches 1970-01-01 00:00:00 +0000 |
29 | +++ .pc/.quilt_patches 2012-11-13 09:46:40 +0000 |
30 | @@ -0,0 +1,1 @@ |
31 | +debian/patches |
32 | |
33 | === added file '.pc/.quilt_series' |
34 | --- .pc/.quilt_series 1970-01-01 00:00:00 +0000 |
35 | +++ .pc/.quilt_series 2012-11-13 09:46:40 +0000 |
36 | @@ -0,0 +1,1 @@ |
37 | +series |
38 | |
39 | === removed directory '.pc/0001-Compile-tccasm.c-conditionally-TCC_CONFIG_ASM.patch' |
40 | === removed file '.pc/0001-Compile-tccasm.c-conditionally-TCC_CONFIG_ASM.patch/tccasm.c' |
41 | --- .pc/0001-Compile-tccasm.c-conditionally-TCC_CONFIG_ASM.patch/tccasm.c 2012-03-06 00:19:03 +0000 |
42 | +++ .pc/0001-Compile-tccasm.c-conditionally-TCC_CONFIG_ASM.patch/tccasm.c 1970-01-01 00:00:00 +0000 |
43 | @@ -1,1117 +0,0 @@ |
44 | -/* |
45 | - * GAS like assembler for TCC |
46 | - * |
47 | - * Copyright (c) 2001-2004 Fabrice Bellard |
48 | - * |
49 | - * This library is free software; you can redistribute it and/or |
50 | - * modify it under the terms of the GNU Lesser General Public |
51 | - * License as published by the Free Software Foundation; either |
52 | - * version 2 of the License, or (at your option) any later version. |
53 | - * |
54 | - * This library is distributed in the hope that it will be useful, |
55 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
56 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
57 | - * Lesser General Public License for more details. |
58 | - * |
59 | - * You should have received a copy of the GNU Lesser General Public |
60 | - * License along with this library; if not, write to the Free Software |
61 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
62 | - */ |
63 | - |
64 | -#include "tcc.h" |
65 | - |
66 | -ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n) |
67 | -{ |
68 | - char buf[64]; |
69 | - TokenSym *ts; |
70 | - |
71 | - snprintf(buf, sizeof(buf), "L..%u", n); |
72 | - ts = tok_alloc(buf, strlen(buf)); |
73 | - return ts->tok; |
74 | -} |
75 | - |
76 | -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe); |
77 | - |
78 | -/* We do not use the C expression parser to handle symbols. Maybe the |
79 | - C expression parser could be tweaked to do so. */ |
80 | - |
81 | -static void asm_expr_unary(TCCState *s1, ExprValue *pe) |
82 | -{ |
83 | - Sym *sym; |
84 | - int op, n, label; |
85 | - const char *p; |
86 | - |
87 | - switch(tok) { |
88 | - case TOK_PPNUM: |
89 | - p = tokc.cstr->data; |
90 | - n = strtoul(p, (char **)&p, 0); |
91 | - if (*p == 'b' || *p == 'f') { |
92 | - /* backward or forward label */ |
93 | - label = asm_get_local_label_name(s1, n); |
94 | - sym = label_find(label); |
95 | - if (*p == 'b') { |
96 | - /* backward : find the last corresponding defined label */ |
97 | - if (sym && sym->r == 0) |
98 | - sym = sym->prev_tok; |
99 | - if (!sym) |
100 | - tcc_error("local label '%d' not found backward", n); |
101 | - } else { |
102 | - /* forward */ |
103 | - if (!sym || sym->r) { |
104 | - /* if the last label is defined, then define a new one */ |
105 | - sym = label_push(&s1->asm_labels, label, 0); |
106 | - sym->type.t = VT_STATIC | VT_VOID; |
107 | - } |
108 | - } |
109 | - pe->v = 0; |
110 | - pe->sym = sym; |
111 | - } else if (*p == '\0') { |
112 | - pe->v = n; |
113 | - pe->sym = NULL; |
114 | - } else { |
115 | - tcc_error("invalid number syntax"); |
116 | - } |
117 | - next(); |
118 | - break; |
119 | - case '+': |
120 | - next(); |
121 | - asm_expr_unary(s1, pe); |
122 | - break; |
123 | - case '-': |
124 | - case '~': |
125 | - op = tok; |
126 | - next(); |
127 | - asm_expr_unary(s1, pe); |
128 | - if (pe->sym) |
129 | - tcc_error("invalid operation with label"); |
130 | - if (op == '-') |
131 | - pe->v = -pe->v; |
132 | - else |
133 | - pe->v = ~pe->v; |
134 | - break; |
135 | - case TOK_CCHAR: |
136 | - case TOK_LCHAR: |
137 | - pe->v = tokc.i; |
138 | - pe->sym = NULL; |
139 | - next(); |
140 | - break; |
141 | - case '(': |
142 | - next(); |
143 | - asm_expr(s1, pe); |
144 | - skip(')'); |
145 | - break; |
146 | - default: |
147 | - if (tok >= TOK_IDENT) { |
148 | - /* label case : if the label was not found, add one */ |
149 | - sym = label_find(tok); |
150 | - if (!sym) { |
151 | - sym = label_push(&s1->asm_labels, tok, 0); |
152 | - /* NOTE: by default, the symbol is global */ |
153 | - sym->type.t = VT_VOID; |
154 | - } |
155 | - if (sym->r == SHN_ABS) { |
156 | - /* if absolute symbol, no need to put a symbol value */ |
157 | - pe->v = sym->jnext; |
158 | - pe->sym = NULL; |
159 | - } else { |
160 | - pe->v = 0; |
161 | - pe->sym = sym; |
162 | - } |
163 | - next(); |
164 | - } else { |
165 | - tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc)); |
166 | - } |
167 | - break; |
168 | - } |
169 | -} |
170 | - |
171 | -static void asm_expr_prod(TCCState *s1, ExprValue *pe) |
172 | -{ |
173 | - int op; |
174 | - ExprValue e2; |
175 | - |
176 | - asm_expr_unary(s1, pe); |
177 | - for(;;) { |
178 | - op = tok; |
179 | - if (op != '*' && op != '/' && op != '%' && |
180 | - op != TOK_SHL && op != TOK_SAR) |
181 | - break; |
182 | - next(); |
183 | - asm_expr_unary(s1, &e2); |
184 | - if (pe->sym || e2.sym) |
185 | - tcc_error("invalid operation with label"); |
186 | - switch(op) { |
187 | - case '*': |
188 | - pe->v *= e2.v; |
189 | - break; |
190 | - case '/': |
191 | - if (e2.v == 0) { |
192 | - div_error: |
193 | - tcc_error("division by zero"); |
194 | - } |
195 | - pe->v /= e2.v; |
196 | - break; |
197 | - case '%': |
198 | - if (e2.v == 0) |
199 | - goto div_error; |
200 | - pe->v %= e2.v; |
201 | - break; |
202 | - case TOK_SHL: |
203 | - pe->v <<= e2.v; |
204 | - break; |
205 | - default: |
206 | - case TOK_SAR: |
207 | - pe->v >>= e2.v; |
208 | - break; |
209 | - } |
210 | - } |
211 | -} |
212 | - |
213 | -static void asm_expr_logic(TCCState *s1, ExprValue *pe) |
214 | -{ |
215 | - int op; |
216 | - ExprValue e2; |
217 | - |
218 | - asm_expr_prod(s1, pe); |
219 | - for(;;) { |
220 | - op = tok; |
221 | - if (op != '&' && op != '|' && op != '^') |
222 | - break; |
223 | - next(); |
224 | - asm_expr_prod(s1, &e2); |
225 | - if (pe->sym || e2.sym) |
226 | - tcc_error("invalid operation with label"); |
227 | - switch(op) { |
228 | - case '&': |
229 | - pe->v &= e2.v; |
230 | - break; |
231 | - case '|': |
232 | - pe->v |= e2.v; |
233 | - break; |
234 | - default: |
235 | - case '^': |
236 | - pe->v ^= e2.v; |
237 | - break; |
238 | - } |
239 | - } |
240 | -} |
241 | - |
242 | -static inline void asm_expr_sum(TCCState *s1, ExprValue *pe) |
243 | -{ |
244 | - int op; |
245 | - ExprValue e2; |
246 | - |
247 | - asm_expr_logic(s1, pe); |
248 | - for(;;) { |
249 | - op = tok; |
250 | - if (op != '+' && op != '-') |
251 | - break; |
252 | - next(); |
253 | - asm_expr_logic(s1, &e2); |
254 | - if (op == '+') { |
255 | - if (pe->sym != NULL && e2.sym != NULL) |
256 | - goto cannot_relocate; |
257 | - pe->v += e2.v; |
258 | - if (pe->sym == NULL && e2.sym != NULL) |
259 | - pe->sym = e2.sym; |
260 | - } else { |
261 | - pe->v -= e2.v; |
262 | - /* NOTE: we are less powerful than gas in that case |
263 | - because we store only one symbol in the expression */ |
264 | - if (!pe->sym && !e2.sym) { |
265 | - /* OK */ |
266 | - } else if (pe->sym && !e2.sym) { |
267 | - /* OK */ |
268 | - } else if (pe->sym && e2.sym) { |
269 | - if (pe->sym == e2.sym) { |
270 | - /* OK */ |
271 | - } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) { |
272 | - /* we also accept defined symbols in the same section */ |
273 | - pe->v += pe->sym->jnext - e2.sym->jnext; |
274 | - } else { |
275 | - goto cannot_relocate; |
276 | - } |
277 | - pe->sym = NULL; /* same symbols can be substracted to NULL */ |
278 | - } else { |
279 | - cannot_relocate: |
280 | - tcc_error("invalid operation with label"); |
281 | - } |
282 | - } |
283 | - } |
284 | -} |
285 | - |
286 | -ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe) |
287 | -{ |
288 | - asm_expr_sum(s1, pe); |
289 | -} |
290 | - |
291 | -ST_FUNC int asm_int_expr(TCCState *s1) |
292 | -{ |
293 | - ExprValue e; |
294 | - asm_expr(s1, &e); |
295 | - if (e.sym) |
296 | - expect("constant"); |
297 | - return e.v; |
298 | -} |
299 | - |
300 | -/* NOTE: the same name space as C labels is used to avoid using too |
301 | - much memory when storing labels in TokenStrings */ |
302 | -static void asm_new_label1(TCCState *s1, int label, int is_local, |
303 | - int sh_num, int value) |
304 | -{ |
305 | - Sym *sym; |
306 | - |
307 | - sym = label_find(label); |
308 | - if (sym) { |
309 | - if (sym->r) { |
310 | - /* the label is already defined */ |
311 | - if (!is_local) { |
312 | - tcc_error("assembler label '%s' already defined", |
313 | - get_tok_str(label, NULL)); |
314 | - } else { |
315 | - /* redefinition of local labels is possible */ |
316 | - goto new_label; |
317 | - } |
318 | - } |
319 | - } else { |
320 | - new_label: |
321 | - sym = label_push(&s1->asm_labels, label, 0); |
322 | - sym->type.t = VT_STATIC | VT_VOID; |
323 | - } |
324 | - sym->r = sh_num; |
325 | - sym->jnext = value; |
326 | -} |
327 | - |
328 | -static void asm_new_label(TCCState *s1, int label, int is_local) |
329 | -{ |
330 | - asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind); |
331 | -} |
332 | - |
333 | -static void asm_free_labels(TCCState *st) |
334 | -{ |
335 | - Sym *s, *s1; |
336 | - Section *sec; |
337 | - |
338 | - for(s = st->asm_labels; s != NULL; s = s1) { |
339 | - s1 = s->prev; |
340 | - /* define symbol value in object file */ |
341 | - if (s->r) { |
342 | - if (s->r == SHN_ABS) |
343 | - sec = SECTION_ABS; |
344 | - else |
345 | - sec = st->sections[s->r]; |
346 | - put_extern_sym2(s, sec, s->jnext, 0, 0); |
347 | - } |
348 | - /* remove label */ |
349 | - table_ident[s->v - TOK_IDENT]->sym_label = NULL; |
350 | - sym_free(s); |
351 | - } |
352 | - st->asm_labels = NULL; |
353 | -} |
354 | - |
355 | -static void use_section1(TCCState *s1, Section *sec) |
356 | -{ |
357 | - cur_text_section->data_offset = ind; |
358 | - cur_text_section = sec; |
359 | - ind = cur_text_section->data_offset; |
360 | -} |
361 | - |
362 | -static void use_section(TCCState *s1, const char *name) |
363 | -{ |
364 | - Section *sec; |
365 | - sec = find_section(s1, name); |
366 | - use_section1(s1, sec); |
367 | -} |
368 | - |
369 | -static void asm_parse_directive(TCCState *s1) |
370 | -{ |
371 | - int n, offset, v, size, tok1; |
372 | - Section *sec; |
373 | - uint8_t *ptr; |
374 | - |
375 | - /* assembler directive */ |
376 | - next(); |
377 | - sec = cur_text_section; |
378 | - switch(tok) { |
379 | - case TOK_ASM_align: |
380 | - case TOK_ASM_skip: |
381 | - case TOK_ASM_space: |
382 | - tok1 = tok; |
383 | - next(); |
384 | - n = asm_int_expr(s1); |
385 | - if (tok1 == TOK_ASM_align) { |
386 | - if (n < 0 || (n & (n-1)) != 0) |
387 | - tcc_error("alignment must be a positive power of two"); |
388 | - offset = (ind + n - 1) & -n; |
389 | - size = offset - ind; |
390 | - /* the section must have a compatible alignment */ |
391 | - if (sec->sh_addralign < n) |
392 | - sec->sh_addralign = n; |
393 | - } else { |
394 | - size = n; |
395 | - } |
396 | - v = 0; |
397 | - if (tok == ',') { |
398 | - next(); |
399 | - v = asm_int_expr(s1); |
400 | - } |
401 | - zero_pad: |
402 | - if (sec->sh_type != SHT_NOBITS) { |
403 | - sec->data_offset = ind; |
404 | - ptr = section_ptr_add(sec, size); |
405 | - memset(ptr, v, size); |
406 | - } |
407 | - ind += size; |
408 | - break; |
409 | - case TOK_ASM_quad: |
410 | - next(); |
411 | - for(;;) { |
412 | - uint64_t vl; |
413 | - const char *p; |
414 | - |
415 | - p = tokc.cstr->data; |
416 | - if (tok != TOK_PPNUM) { |
417 | - error_constant: |
418 | - tcc_error("64 bit constant"); |
419 | - } |
420 | - vl = strtoll(p, (char **)&p, 0); |
421 | - if (*p != '\0') |
422 | - goto error_constant; |
423 | - next(); |
424 | - if (sec->sh_type != SHT_NOBITS) { |
425 | - /* XXX: endianness */ |
426 | - gen_le32(vl); |
427 | - gen_le32(vl >> 32); |
428 | - } else { |
429 | - ind += 8; |
430 | - } |
431 | - if (tok != ',') |
432 | - break; |
433 | - next(); |
434 | - } |
435 | - break; |
436 | - case TOK_ASM_byte: |
437 | - size = 1; |
438 | - goto asm_data; |
439 | - case TOK_ASM_word: |
440 | - case TOK_SHORT: |
441 | - size = 2; |
442 | - goto asm_data; |
443 | - case TOK_LONG: |
444 | - case TOK_INT: |
445 | - size = 4; |
446 | - asm_data: |
447 | - next(); |
448 | - for(;;) { |
449 | - ExprValue e; |
450 | - asm_expr(s1, &e); |
451 | - if (sec->sh_type != SHT_NOBITS) { |
452 | - if (size == 4) { |
453 | - gen_expr32(&e); |
454 | - } else { |
455 | - if (e.sym) |
456 | - expect("constant"); |
457 | - if (size == 1) |
458 | - g(e.v); |
459 | - else |
460 | - gen_le16(e.v); |
461 | - } |
462 | - } else { |
463 | - ind += size; |
464 | - } |
465 | - if (tok != ',') |
466 | - break; |
467 | - next(); |
468 | - } |
469 | - break; |
470 | - case TOK_ASM_fill: |
471 | - { |
472 | - int repeat, size, val, i, j; |
473 | - uint8_t repeat_buf[8]; |
474 | - next(); |
475 | - repeat = asm_int_expr(s1); |
476 | - if (repeat < 0) { |
477 | - tcc_error("repeat < 0; .fill ignored"); |
478 | - break; |
479 | - } |
480 | - size = 1; |
481 | - val = 0; |
482 | - if (tok == ',') { |
483 | - next(); |
484 | - size = asm_int_expr(s1); |
485 | - if (size < 0) { |
486 | - tcc_error("size < 0; .fill ignored"); |
487 | - break; |
488 | - } |
489 | - if (size > 8) |
490 | - size = 8; |
491 | - if (tok == ',') { |
492 | - next(); |
493 | - val = asm_int_expr(s1); |
494 | - } |
495 | - } |
496 | - /* XXX: endianness */ |
497 | - repeat_buf[0] = val; |
498 | - repeat_buf[1] = val >> 8; |
499 | - repeat_buf[2] = val >> 16; |
500 | - repeat_buf[3] = val >> 24; |
501 | - repeat_buf[4] = 0; |
502 | - repeat_buf[5] = 0; |
503 | - repeat_buf[6] = 0; |
504 | - repeat_buf[7] = 0; |
505 | - for(i = 0; i < repeat; i++) { |
506 | - for(j = 0; j < size; j++) { |
507 | - g(repeat_buf[j]); |
508 | - } |
509 | - } |
510 | - } |
511 | - break; |
512 | - case TOK_ASM_org: |
513 | - { |
514 | - unsigned long n; |
515 | - next(); |
516 | - /* XXX: handle section symbols too */ |
517 | - n = asm_int_expr(s1); |
518 | - if (n < ind) |
519 | - tcc_error("attempt to .org backwards"); |
520 | - v = 0; |
521 | - size = n - ind; |
522 | - goto zero_pad; |
523 | - } |
524 | - break; |
525 | - case TOK_ASM_globl: |
526 | - case TOK_ASM_global: |
527 | - case TOK_ASM_weak: |
528 | - tok1 = tok; |
529 | - do { |
530 | - Sym *sym; |
531 | - |
532 | - next(); |
533 | - sym = label_find(tok); |
534 | - if (!sym) { |
535 | - sym = label_push(&s1->asm_labels, tok, 0); |
536 | - sym->type.t = VT_VOID; |
537 | - } |
538 | - sym->type.t &= ~VT_STATIC; |
539 | - if (tok1 == TOK_ASM_weak) |
540 | - sym->type.t |= VT_WEAK; |
541 | - next(); |
542 | - } while (tok == ','); |
543 | - break; |
544 | - case TOK_ASM_string: |
545 | - case TOK_ASM_ascii: |
546 | - case TOK_ASM_asciz: |
547 | - { |
548 | - const uint8_t *p; |
549 | - int i, size, t; |
550 | - |
551 | - t = tok; |
552 | - next(); |
553 | - for(;;) { |
554 | - if (tok != TOK_STR) |
555 | - expect("string constant"); |
556 | - p = tokc.cstr->data; |
557 | - size = tokc.cstr->size; |
558 | - if (t == TOK_ASM_ascii && size > 0) |
559 | - size--; |
560 | - for(i = 0; i < size; i++) |
561 | - g(p[i]); |
562 | - next(); |
563 | - if (tok == ',') { |
564 | - next(); |
565 | - } else if (tok != TOK_STR) { |
566 | - break; |
567 | - } |
568 | - } |
569 | - } |
570 | - break; |
571 | - case TOK_ASM_text: |
572 | - case TOK_ASM_data: |
573 | - case TOK_ASM_bss: |
574 | - { |
575 | - char sname[64]; |
576 | - tok1 = tok; |
577 | - n = 0; |
578 | - next(); |
579 | - if (tok != ';' && tok != TOK_LINEFEED) { |
580 | - n = asm_int_expr(s1); |
581 | - next(); |
582 | - } |
583 | - sprintf(sname, (n?".%s%d":".%s"), get_tok_str(tok1, NULL), n); |
584 | - use_section(s1, sname); |
585 | - } |
586 | - break; |
587 | - case TOK_ASM_file: |
588 | - { |
589 | - char filename[512]; |
590 | - |
591 | - filename[0] = '\0'; |
592 | - next(); |
593 | - |
594 | - if (tok == TOK_STR) |
595 | - pstrcat(filename, sizeof(filename), tokc.cstr->data); |
596 | - else |
597 | - pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); |
598 | - |
599 | - if (s1->warn_unsupported) |
600 | - tcc_warning("ignoring .file %s", filename); |
601 | - |
602 | - next(); |
603 | - } |
604 | - break; |
605 | - case TOK_ASM_ident: |
606 | - { |
607 | - char ident[256]; |
608 | - |
609 | - ident[0] = '\0'; |
610 | - next(); |
611 | - |
612 | - if (tok == TOK_STR) |
613 | - pstrcat(ident, sizeof(ident), tokc.cstr->data); |
614 | - else |
615 | - pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); |
616 | - |
617 | - if (s1->warn_unsupported) |
618 | - tcc_warning("ignoring .ident %s", ident); |
619 | - |
620 | - next(); |
621 | - } |
622 | - break; |
623 | - case TOK_ASM_size: |
624 | - { |
625 | - Sym *sym; |
626 | - |
627 | - next(); |
628 | - sym = label_find(tok); |
629 | - if (!sym) { |
630 | - tcc_error("label not found: %s", get_tok_str(tok, NULL)); |
631 | - } |
632 | - |
633 | - next(); |
634 | - skip(','); |
635 | - /* XXX .size name,label2-label1 */ |
636 | - if (s1->warn_unsupported) |
637 | - tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); |
638 | - |
639 | - while (tok != '\n' && tok != CH_EOF) { |
640 | - next(); |
641 | - } |
642 | - } |
643 | - break; |
644 | - case TOK_ASM_type: |
645 | - { |
646 | - Sym *sym; |
647 | - const char *newtype; |
648 | - |
649 | - next(); |
650 | - sym = label_find(tok); |
651 | - if (!sym) { |
652 | - sym = label_push(&s1->asm_labels, tok, 0); |
653 | - sym->type.t = VT_VOID; |
654 | - } |
655 | - |
656 | - next(); |
657 | - skip(','); |
658 | - if (tok == TOK_STR) { |
659 | - newtype = tokc.cstr->data; |
660 | - } else { |
661 | - if (tok == '@' || tok == '%') |
662 | - skip(tok); |
663 | - newtype = get_tok_str(tok, NULL); |
664 | - } |
665 | - |
666 | - if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { |
667 | - sym->type.t = VT_FUNC; |
668 | - } |
669 | - else if (s1->warn_unsupported) |
670 | - tcc_warning("change type of '%s' from 0x%x to '%s' ignored", |
671 | - get_tok_str(sym->v, NULL), sym->type.t, newtype); |
672 | - |
673 | - next(); |
674 | - } |
675 | - break; |
676 | - case TOK_SECTION1: |
677 | - { |
678 | - char sname[256]; |
679 | - |
680 | - /* XXX: support more options */ |
681 | - next(); |
682 | - sname[0] = '\0'; |
683 | - while (tok != ';' && tok != TOK_LINEFEED && tok != ',') { |
684 | - if (tok == TOK_STR) |
685 | - pstrcat(sname, sizeof(sname), tokc.cstr->data); |
686 | - else |
687 | - pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL)); |
688 | - next(); |
689 | - } |
690 | - if (tok == ',') { |
691 | - /* skip section options */ |
692 | - next(); |
693 | - if (tok != TOK_STR) |
694 | - expect("string constant"); |
695 | - next(); |
696 | - } |
697 | - last_text_section = cur_text_section; |
698 | - use_section(s1, sname); |
699 | - } |
700 | - break; |
701 | - case TOK_ASM_previous: |
702 | - { |
703 | - Section *sec; |
704 | - next(); |
705 | - if (!last_text_section) |
706 | - tcc_error("no previous section referenced"); |
707 | - sec = cur_text_section; |
708 | - use_section1(s1, last_text_section); |
709 | - last_text_section = sec; |
710 | - } |
711 | - break; |
712 | -#ifdef TCC_TARGET_I386 |
713 | - case TOK_ASM_code16: |
714 | - { |
715 | - next(); |
716 | - s1->seg_size = 16; |
717 | - } |
718 | - break; |
719 | - case TOK_ASM_code32: |
720 | - { |
721 | - next(); |
722 | - s1->seg_size = 32; |
723 | - } |
724 | - break; |
725 | -#endif |
726 | -#ifdef TCC_TARGET_X86_64 |
727 | - /* added for compatibility with GAS */ |
728 | - case TOK_ASM_code64: |
729 | - next(); |
730 | - break; |
731 | -#endif |
732 | - default: |
733 | - tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL)); |
734 | - break; |
735 | - } |
736 | -} |
737 | - |
738 | - |
739 | -/* assemble a file */ |
740 | -static int tcc_assemble_internal(TCCState *s1, int do_preprocess) |
741 | -{ |
742 | - int opcode; |
743 | - |
744 | -#if 0 |
745 | - /* print stats about opcodes */ |
746 | - { |
747 | - const ASMInstr *pa; |
748 | - int freq[4]; |
749 | - int op_vals[500]; |
750 | - int nb_op_vals, i, j; |
751 | - |
752 | - nb_op_vals = 0; |
753 | - memset(freq, 0, sizeof(freq)); |
754 | - for(pa = asm_instrs; pa->sym != 0; pa++) { |
755 | - freq[pa->nb_ops]++; |
756 | - for(i=0;i<pa->nb_ops;i++) { |
757 | - for(j=0;j<nb_op_vals;j++) { |
758 | - if (pa->op_type[i] == op_vals[j]) |
759 | - goto found; |
760 | - } |
761 | - op_vals[nb_op_vals++] = pa->op_type[i]; |
762 | - found: ; |
763 | - } |
764 | - } |
765 | - for(i=0;i<nb_op_vals;i++) { |
766 | - int v = op_vals[i]; |
767 | - if ((v & (v - 1)) != 0) |
768 | - printf("%3d: %08x\n", i, v); |
769 | - } |
770 | - printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n", |
771 | - sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr), |
772 | - freq[0], freq[1], freq[2], freq[3]); |
773 | - } |
774 | -#endif |
775 | - |
776 | - /* XXX: undefine C labels */ |
777 | - |
778 | - ch = file->buf_ptr[0]; |
779 | - tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF; |
780 | - parse_flags = PARSE_FLAG_ASM_COMMENTS; |
781 | - if (do_preprocess) |
782 | - parse_flags |= PARSE_FLAG_PREPROCESS; |
783 | - next(); |
784 | - for(;;) { |
785 | - if (tok == TOK_EOF) |
786 | - break; |
787 | - parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ |
788 | - redo: |
789 | - if (tok == '#') { |
790 | - /* horrible gas comment */ |
791 | - while (tok != TOK_LINEFEED) |
792 | - next(); |
793 | - } else if (tok == '.') { |
794 | - asm_parse_directive(s1); |
795 | - } else if (tok == TOK_PPNUM) { |
796 | - const char *p; |
797 | - int n; |
798 | - p = tokc.cstr->data; |
799 | - n = strtoul(p, (char **)&p, 10); |
800 | - if (*p != '\0') |
801 | - expect("':'"); |
802 | - /* new local label */ |
803 | - asm_new_label(s1, asm_get_local_label_name(s1, n), 1); |
804 | - next(); |
805 | - skip(':'); |
806 | - goto redo; |
807 | - } else if (tok >= TOK_IDENT) { |
808 | - /* instruction or label */ |
809 | - opcode = tok; |
810 | - next(); |
811 | - if (tok == ':') { |
812 | - /* new label */ |
813 | - asm_new_label(s1, opcode, 0); |
814 | - next(); |
815 | - goto redo; |
816 | - } else if (tok == '=') { |
817 | - int n; |
818 | - next(); |
819 | - n = asm_int_expr(s1); |
820 | - asm_new_label1(s1, opcode, 0, SHN_ABS, n); |
821 | - goto redo; |
822 | - } else { |
823 | - asm_opcode(s1, opcode); |
824 | - } |
825 | - } |
826 | - /* end of line */ |
827 | - if (tok != ';' && tok != TOK_LINEFEED){ |
828 | - expect("end of line"); |
829 | - } |
830 | - parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */ |
831 | - next(); |
832 | - } |
833 | - |
834 | - asm_free_labels(s1); |
835 | - |
836 | - return 0; |
837 | -} |
838 | - |
839 | -/* Assemble the current file */ |
840 | -ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess) |
841 | -{ |
842 | - Sym *define_start; |
843 | - int ret; |
844 | - |
845 | - preprocess_init(s1); |
846 | - |
847 | - /* default section is text */ |
848 | - cur_text_section = text_section; |
849 | - ind = cur_text_section->data_offset; |
850 | - |
851 | - define_start = define_stack; |
852 | - |
853 | - /* an elf symbol of type STT_FILE must be put so that STB_LOCAL |
854 | - symbols can be safely used */ |
855 | - put_elf_sym(symtab_section, 0, 0, |
856 | - ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0, |
857 | - SHN_ABS, file->filename); |
858 | - |
859 | - ret = tcc_assemble_internal(s1, do_preprocess); |
860 | - |
861 | - cur_text_section->data_offset = ind; |
862 | - |
863 | - free_defines(define_start); |
864 | - |
865 | - return ret; |
866 | -} |
867 | - |
868 | -/********************************************************************/ |
869 | -/* GCC inline asm support */ |
870 | - |
871 | -/* assemble the string 'str' in the current C compilation unit without |
872 | - C preprocessing. NOTE: str is modified by modifying the '\0' at the |
873 | - end */ |
874 | -static void tcc_assemble_inline(TCCState *s1, char *str, int len) |
875 | -{ |
876 | - int saved_parse_flags; |
877 | - const int *saved_macro_ptr; |
878 | - |
879 | - saved_parse_flags = parse_flags; |
880 | - saved_macro_ptr = macro_ptr; |
881 | - |
882 | - tcc_open_bf(s1, file->filename, len); |
883 | - file->line_num = file->prev->line_num; |
884 | - memcpy(file->buffer, str, len); |
885 | - |
886 | - macro_ptr = NULL; |
887 | - tcc_assemble_internal(s1, 0); |
888 | - tcc_close(); |
889 | - |
890 | - parse_flags = saved_parse_flags; |
891 | - macro_ptr = saved_macro_ptr; |
892 | -} |
893 | - |
894 | -/* find a constraint by its number or id (gcc 3 extended |
895 | - syntax). return -1 if not found. Return in *pp in char after the |
896 | - constraint */ |
897 | -ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands, |
898 | - const char *name, const char **pp) |
899 | -{ |
900 | - int index; |
901 | - TokenSym *ts; |
902 | - const char *p; |
903 | - |
904 | - if (isnum(*name)) { |
905 | - index = 0; |
906 | - while (isnum(*name)) { |
907 | - index = (index * 10) + (*name) - '0'; |
908 | - name++; |
909 | - } |
910 | - if ((unsigned)index >= nb_operands) |
911 | - index = -1; |
912 | - } else if (*name == '[') { |
913 | - name++; |
914 | - p = strchr(name, ']'); |
915 | - if (p) { |
916 | - ts = tok_alloc(name, p - name); |
917 | - for(index = 0; index < nb_operands; index++) { |
918 | - if (operands[index].id == ts->tok) |
919 | - goto found; |
920 | - } |
921 | - index = -1; |
922 | - found: |
923 | - name = p + 1; |
924 | - } else { |
925 | - index = -1; |
926 | - } |
927 | - } else { |
928 | - index = -1; |
929 | - } |
930 | - if (pp) |
931 | - *pp = name; |
932 | - return index; |
933 | -} |
934 | - |
935 | -static void subst_asm_operands(ASMOperand *operands, int nb_operands, |
936 | - int nb_outputs, |
937 | - CString *out_str, CString *in_str) |
938 | -{ |
939 | - int c, index, modifier; |
940 | - const char *str; |
941 | - ASMOperand *op; |
942 | - SValue sv; |
943 | - |
944 | - cstr_new(out_str); |
945 | - str = in_str->data; |
946 | - for(;;) { |
947 | - c = *str++; |
948 | - if (c == '%') { |
949 | - if (*str == '%') { |
950 | - str++; |
951 | - goto add_char; |
952 | - } |
953 | - modifier = 0; |
954 | - if (*str == 'c' || *str == 'n' || |
955 | - *str == 'b' || *str == 'w' || *str == 'h') |
956 | - modifier = *str++; |
957 | - index = find_constraint(operands, nb_operands, str, &str); |
958 | - if (index < 0) |
959 | - tcc_error("invalid operand reference after %%"); |
960 | - op = &operands[index]; |
961 | - sv = *op->vt; |
962 | - if (op->reg >= 0) { |
963 | - sv.r = op->reg; |
964 | - if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory) |
965 | - sv.r |= VT_LVAL; |
966 | - } |
967 | - subst_asm_operand(out_str, &sv, modifier); |
968 | - } else { |
969 | - add_char: |
970 | - cstr_ccat(out_str, c); |
971 | - if (c == '\0') |
972 | - break; |
973 | - } |
974 | - } |
975 | -} |
976 | - |
977 | - |
978 | -static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr, |
979 | - int is_output) |
980 | -{ |
981 | - ASMOperand *op; |
982 | - int nb_operands; |
983 | - |
984 | - if (tok != ':') { |
985 | - nb_operands = *nb_operands_ptr; |
986 | - for(;;) { |
987 | - if (nb_operands >= MAX_ASM_OPERANDS) |
988 | - tcc_error("too many asm operands"); |
989 | - op = &operands[nb_operands++]; |
990 | - op->id = 0; |
991 | - if (tok == '[') { |
992 | - next(); |
993 | - if (tok < TOK_IDENT) |
994 | - expect("identifier"); |
995 | - op->id = tok; |
996 | - next(); |
997 | - skip(']'); |
998 | - } |
999 | - if (tok != TOK_STR) |
1000 | - expect("string constant"); |
1001 | - op->constraint = tcc_malloc(tokc.cstr->size); |
1002 | - strcpy(op->constraint, tokc.cstr->data); |
1003 | - next(); |
1004 | - skip('('); |
1005 | - gexpr(); |
1006 | - if (is_output) { |
1007 | - test_lvalue(); |
1008 | - } else { |
1009 | - /* we want to avoid LLOCAL case, except when the 'm' |
1010 | - constraint is used. Note that it may come from |
1011 | - register storage, so we need to convert (reg) |
1012 | - case */ |
1013 | - if ((vtop->r & VT_LVAL) && |
1014 | - ((vtop->r & VT_VALMASK) == VT_LLOCAL || |
1015 | - (vtop->r & VT_VALMASK) < VT_CONST) && |
1016 | - !strchr(op->constraint, 'm')) { |
1017 | - gv(RC_INT); |
1018 | - } |
1019 | - } |
1020 | - op->vt = vtop; |
1021 | - skip(')'); |
1022 | - if (tok == ',') { |
1023 | - next(); |
1024 | - } else { |
1025 | - break; |
1026 | - } |
1027 | - } |
1028 | - *nb_operands_ptr = nb_operands; |
1029 | - } |
1030 | -} |
1031 | - |
1032 | -/* parse the GCC asm() instruction */ |
1033 | -ST_FUNC void asm_instr(void) |
1034 | -{ |
1035 | - CString astr, astr1; |
1036 | - ASMOperand operands[MAX_ASM_OPERANDS]; |
1037 | - int nb_outputs, nb_operands, i, must_subst, out_reg; |
1038 | - uint8_t clobber_regs[NB_ASM_REGS]; |
1039 | - |
1040 | - next(); |
1041 | - /* since we always generate the asm() instruction, we can ignore |
1042 | - volatile */ |
1043 | - if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) { |
1044 | - next(); |
1045 | - } |
1046 | - parse_asm_str(&astr); |
1047 | - nb_operands = 0; |
1048 | - nb_outputs = 0; |
1049 | - must_subst = 0; |
1050 | - memset(clobber_regs, 0, sizeof(clobber_regs)); |
1051 | - if (tok == ':') { |
1052 | - next(); |
1053 | - must_subst = 1; |
1054 | - /* output args */ |
1055 | - parse_asm_operands(operands, &nb_operands, 1); |
1056 | - nb_outputs = nb_operands; |
1057 | - if (tok == ':') { |
1058 | - next(); |
1059 | - if (tok != ')') { |
1060 | - /* input args */ |
1061 | - parse_asm_operands(operands, &nb_operands, 0); |
1062 | - if (tok == ':') { |
1063 | - /* clobber list */ |
1064 | - /* XXX: handle registers */ |
1065 | - next(); |
1066 | - for(;;) { |
1067 | - if (tok != TOK_STR) |
1068 | - expect("string constant"); |
1069 | - asm_clobber(clobber_regs, tokc.cstr->data); |
1070 | - next(); |
1071 | - if (tok == ',') { |
1072 | - next(); |
1073 | - } else { |
1074 | - break; |
1075 | - } |
1076 | - } |
1077 | - } |
1078 | - } |
1079 | - } |
1080 | - } |
1081 | - skip(')'); |
1082 | - /* NOTE: we do not eat the ';' so that we can restore the current |
1083 | - token after the assembler parsing */ |
1084 | - if (tok != ';') |
1085 | - expect("';'"); |
1086 | - |
1087 | - /* save all values in the memory */ |
1088 | - save_regs(0); |
1089 | - |
1090 | - /* compute constraints */ |
1091 | - asm_compute_constraints(operands, nb_operands, nb_outputs, |
1092 | - clobber_regs, &out_reg); |
1093 | - |
1094 | - /* substitute the operands in the asm string. No substitution is |
1095 | - done if no operands (GCC behaviour) */ |
1096 | -#ifdef ASM_DEBUG |
1097 | - printf("asm: \"%s\"\n", (char *)astr.data); |
1098 | -#endif |
1099 | - if (must_subst) { |
1100 | - subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr); |
1101 | - cstr_free(&astr); |
1102 | - } else { |
1103 | - astr1 = astr; |
1104 | - } |
1105 | -#ifdef ASM_DEBUG |
1106 | - printf("subst_asm: \"%s\"\n", (char *)astr1.data); |
1107 | -#endif |
1108 | - |
1109 | - /* generate loads */ |
1110 | - asm_gen_code(operands, nb_operands, nb_outputs, 0, |
1111 | - clobber_regs, out_reg); |
1112 | - |
1113 | - /* assemble the string with tcc internal assembler */ |
1114 | - tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1); |
1115 | - |
1116 | - /* restore the current C token */ |
1117 | - next(); |
1118 | - |
1119 | - /* store the output values if needed */ |
1120 | - asm_gen_code(operands, nb_operands, nb_outputs, 1, |
1121 | - clobber_regs, out_reg); |
1122 | - |
1123 | - /* free everything */ |
1124 | - for(i=0;i<nb_operands;i++) { |
1125 | - ASMOperand *op; |
1126 | - op = &operands[i]; |
1127 | - tcc_free(op->constraint); |
1128 | - vpop(); |
1129 | - } |
1130 | - cstr_free(&astr1); |
1131 | -} |
1132 | - |
1133 | -ST_FUNC void asm_global_instr(void) |
1134 | -{ |
1135 | - CString astr; |
1136 | - |
1137 | - next(); |
1138 | - parse_asm_str(&astr); |
1139 | - skip(')'); |
1140 | - /* NOTE: we do not eat the ';' so that we can restore the current |
1141 | - token after the assembler parsing */ |
1142 | - if (tok != ';') |
1143 | - expect("';'"); |
1144 | - |
1145 | -#ifdef ASM_DEBUG |
1146 | - printf("asm_global: \"%s\"\n", (char *)astr.data); |
1147 | -#endif |
1148 | - cur_text_section = text_section; |
1149 | - ind = cur_text_section->data_offset; |
1150 | - |
1151 | - /* assemble the string with tcc internal assembler */ |
1152 | - tcc_assemble_inline(tcc_state, astr.data, astr.size - 1); |
1153 | - |
1154 | - cur_text_section->data_offset = ind; |
1155 | - |
1156 | - /* restore the current C token */ |
1157 | - next(); |
1158 | - |
1159 | - cstr_free(&astr); |
1160 | -} |
1161 | |
1162 | === added directory '.pc/0001-Fix-R_ARM_REL32-relocation.patch' |
1163 | === added file '.pc/0001-Fix-R_ARM_REL32-relocation.patch/tccelf.c' |
1164 | --- .pc/0001-Fix-R_ARM_REL32-relocation.patch/tccelf.c 1970-01-01 00:00:00 +0000 |
1165 | +++ .pc/0001-Fix-R_ARM_REL32-relocation.patch/tccelf.c 2012-11-13 09:46:40 +0000 |
1166 | @@ -0,0 +1,2995 @@ |
1167 | +/* |
1168 | + * ELF file handling for TCC |
1169 | + * |
1170 | + * Copyright (c) 2001-2004 Fabrice Bellard |
1171 | + * |
1172 | + * This library is free software; you can redistribute it and/or |
1173 | + * modify it under the terms of the GNU Lesser General Public |
1174 | + * License as published by the Free Software Foundation; either |
1175 | + * version 2 of the License, or (at your option) any later version. |
1176 | + * |
1177 | + * This library is distributed in the hope that it will be useful, |
1178 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1179 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1180 | + * Lesser General Public License for more details. |
1181 | + * |
1182 | + * You should have received a copy of the GNU Lesser General Public |
1183 | + * License along with this library; if not, write to the Free Software |
1184 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
1185 | + */ |
1186 | + |
1187 | +#include "tcc.h" |
1188 | + |
1189 | +static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */ |
1190 | + |
1191 | +ST_FUNC int put_elf_str(Section *s, const char *sym) |
1192 | +{ |
1193 | + int offset, len; |
1194 | + char *ptr; |
1195 | + |
1196 | + len = strlen(sym) + 1; |
1197 | + offset = s->data_offset; |
1198 | + ptr = section_ptr_add(s, len); |
1199 | + memcpy(ptr, sym, len); |
1200 | + return offset; |
1201 | +} |
1202 | + |
1203 | +/* elf symbol hashing function */ |
1204 | +static unsigned long elf_hash(const unsigned char *name) |
1205 | +{ |
1206 | + unsigned long h = 0, g; |
1207 | + |
1208 | + while (*name) { |
1209 | + h = (h << 4) + *name++; |
1210 | + g = h & 0xf0000000; |
1211 | + if (g) |
1212 | + h ^= g >> 24; |
1213 | + h &= ~g; |
1214 | + } |
1215 | + return h; |
1216 | +} |
1217 | + |
1218 | +/* rebuild hash table of section s */ |
1219 | +/* NOTE: we do factorize the hash table code to go faster */ |
1220 | +static void rebuild_hash(Section *s, unsigned int nb_buckets) |
1221 | +{ |
1222 | + ElfW(Sym) *sym; |
1223 | + int *ptr, *hash, nb_syms, sym_index, h; |
1224 | + char *strtab; |
1225 | + |
1226 | + strtab = s->link->data; |
1227 | + nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
1228 | + |
1229 | + s->hash->data_offset = 0; |
1230 | + ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int)); |
1231 | + ptr[0] = nb_buckets; |
1232 | + ptr[1] = nb_syms; |
1233 | + ptr += 2; |
1234 | + hash = ptr; |
1235 | + memset(hash, 0, (nb_buckets + 1) * sizeof(int)); |
1236 | + ptr += nb_buckets + 1; |
1237 | + |
1238 | + sym = (ElfW(Sym) *)s->data + 1; |
1239 | + for(sym_index = 1; sym_index < nb_syms; sym_index++) { |
1240 | + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
1241 | + h = elf_hash(strtab + sym->st_name) % nb_buckets; |
1242 | + *ptr = hash[h]; |
1243 | + hash[h] = sym_index; |
1244 | + } else { |
1245 | + *ptr = 0; |
1246 | + } |
1247 | + ptr++; |
1248 | + sym++; |
1249 | + } |
1250 | +} |
1251 | + |
1252 | +/* return the symbol number */ |
1253 | +ST_FUNC int put_elf_sym(Section *s, uplong value, unsigned long size, |
1254 | + int info, int other, int shndx, const char *name) |
1255 | +{ |
1256 | + int name_offset, sym_index; |
1257 | + int nbuckets, h; |
1258 | + ElfW(Sym) *sym; |
1259 | + Section *hs; |
1260 | + |
1261 | + sym = section_ptr_add(s, sizeof(ElfW(Sym))); |
1262 | + if (name) |
1263 | + name_offset = put_elf_str(s->link, name); |
1264 | + else |
1265 | + name_offset = 0; |
1266 | + /* XXX: endianness */ |
1267 | + sym->st_name = name_offset; |
1268 | + sym->st_value = value; |
1269 | + sym->st_size = size; |
1270 | + sym->st_info = info; |
1271 | + sym->st_other = other; |
1272 | + sym->st_shndx = shndx; |
1273 | + sym_index = sym - (ElfW(Sym) *)s->data; |
1274 | + hs = s->hash; |
1275 | + if (hs) { |
1276 | + int *ptr, *base; |
1277 | + ptr = section_ptr_add(hs, sizeof(int)); |
1278 | + base = (int *)hs->data; |
1279 | + /* only add global or weak symbols */ |
1280 | + if (ELFW(ST_BIND)(info) != STB_LOCAL) { |
1281 | + /* add another hashing entry */ |
1282 | + nbuckets = base[0]; |
1283 | + h = elf_hash(name) % nbuckets; |
1284 | + *ptr = base[2 + h]; |
1285 | + base[2 + h] = sym_index; |
1286 | + base[1]++; |
1287 | + /* we resize the hash table */ |
1288 | + hs->nb_hashed_syms++; |
1289 | + if (hs->nb_hashed_syms > 2 * nbuckets) { |
1290 | + rebuild_hash(s, 2 * nbuckets); |
1291 | + } |
1292 | + } else { |
1293 | + *ptr = 0; |
1294 | + base[1]++; |
1295 | + } |
1296 | + } |
1297 | + return sym_index; |
1298 | +} |
1299 | + |
1300 | +/* find global ELF symbol 'name' and return its index. Return 0 if not |
1301 | + found. */ |
1302 | +ST_FUNC int find_elf_sym(Section *s, const char *name) |
1303 | +{ |
1304 | + ElfW(Sym) *sym; |
1305 | + Section *hs; |
1306 | + int nbuckets, sym_index, h; |
1307 | + const char *name1; |
1308 | + |
1309 | + hs = s->hash; |
1310 | + if (!hs) |
1311 | + return 0; |
1312 | + nbuckets = ((int *)hs->data)[0]; |
1313 | + h = elf_hash(name) % nbuckets; |
1314 | + sym_index = ((int *)hs->data)[2 + h]; |
1315 | + while (sym_index != 0) { |
1316 | + sym = &((ElfW(Sym) *)s->data)[sym_index]; |
1317 | + name1 = s->link->data + sym->st_name; |
1318 | + if (!strcmp(name, name1)) |
1319 | + return sym_index; |
1320 | + sym_index = ((int *)hs->data)[2 + nbuckets + sym_index]; |
1321 | + } |
1322 | + return 0; |
1323 | +} |
1324 | + |
1325 | +/* return elf symbol value, signal error if 'err' is nonzero */ |
1326 | +static void *get_elf_sym_addr(TCCState *s, const char *name, int err) |
1327 | +{ |
1328 | + int sym_index; |
1329 | + ElfW(Sym) *sym; |
1330 | + |
1331 | + sym_index = find_elf_sym(s->symtab, name); |
1332 | + sym = &((ElfW(Sym) *)s->symtab->data)[sym_index]; |
1333 | + if (!sym_index || sym->st_shndx == SHN_UNDEF) { |
1334 | + if (err) |
1335 | + tcc_error("%s not defined", name); |
1336 | + return NULL; |
1337 | + } |
1338 | + return (void*)(uplong)sym->st_value; |
1339 | +} |
1340 | + |
1341 | +/* return elf symbol value */ |
1342 | +LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name) |
1343 | +{ |
1344 | + return get_elf_sym_addr(s, name, 0); |
1345 | +} |
1346 | + |
1347 | +/* return elf symbol value or error */ |
1348 | +ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name) |
1349 | +{ |
1350 | + return get_elf_sym_addr(s, name, 1); |
1351 | +} |
1352 | + |
1353 | +/* add an elf symbol : check if it is already defined and patch |
1354 | + it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */ |
1355 | +ST_FUNC int add_elf_sym(Section *s, uplong value, unsigned long size, |
1356 | + int info, int other, int sh_num, const char *name) |
1357 | +{ |
1358 | + ElfW(Sym) *esym; |
1359 | + int sym_bind, sym_index, sym_type, esym_bind; |
1360 | + unsigned char sym_vis, esym_vis, new_vis; |
1361 | + |
1362 | + sym_bind = ELFW(ST_BIND)(info); |
1363 | + sym_type = ELFW(ST_TYPE)(info); |
1364 | + sym_vis = ELFW(ST_VISIBILITY)(other); |
1365 | + |
1366 | + if (sym_bind != STB_LOCAL) { |
1367 | + /* we search global or weak symbols */ |
1368 | + sym_index = find_elf_sym(s, name); |
1369 | + if (!sym_index) |
1370 | + goto do_def; |
1371 | + esym = &((ElfW(Sym) *)s->data)[sym_index]; |
1372 | + if (esym->st_shndx != SHN_UNDEF) { |
1373 | + esym_bind = ELFW(ST_BIND)(esym->st_info); |
1374 | + /* propagate the most constraining visibility */ |
1375 | + /* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */ |
1376 | + esym_vis = ELFW(ST_VISIBILITY)(esym->st_other); |
1377 | + if (esym_vis == STV_DEFAULT) { |
1378 | + new_vis = sym_vis; |
1379 | + } else if (sym_vis == STV_DEFAULT) { |
1380 | + new_vis = esym_vis; |
1381 | + } else { |
1382 | + new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis; |
1383 | + } |
1384 | + esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1)) |
1385 | + | new_vis; |
1386 | + other = esym->st_other; /* in case we have to patch esym */ |
1387 | + if (sh_num == SHN_UNDEF) { |
1388 | + /* ignore adding of undefined symbol if the |
1389 | + corresponding symbol is already defined */ |
1390 | + } else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) { |
1391 | + /* global overrides weak, so patch */ |
1392 | + goto do_patch; |
1393 | + } else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) { |
1394 | + /* weak is ignored if already global */ |
1395 | + } else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) { |
1396 | + /* keep first-found weak definition, ignore subsequents */ |
1397 | + } else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) { |
1398 | + /* ignore hidden symbols after */ |
1399 | + } else if (esym->st_shndx == SHN_COMMON |
1400 | + && (sh_num < SHN_LORESERVE || sh_num == SHN_COMMON)) { |
1401 | + /* gr: Happens with 'tcc ... -static tcctest.c' on e.g. Ubuntu 6.01 |
1402 | + No idea if this is the correct solution ... */ |
1403 | + goto do_patch; |
1404 | + } else if (s == tcc_state->dynsymtab_section) { |
1405 | + /* we accept that two DLL define the same symbol */ |
1406 | + } else { |
1407 | +#if 1 |
1408 | + printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n", |
1409 | + sym_bind, sh_num, new_vis, esym_bind, esym->st_shndx, esym_vis); |
1410 | +#endif |
1411 | + tcc_error_noabort("'%s' defined twice", name); |
1412 | + } |
1413 | + } else { |
1414 | + do_patch: |
1415 | + esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type); |
1416 | + esym->st_shndx = sh_num; |
1417 | + new_undef_sym = 1; |
1418 | + esym->st_value = value; |
1419 | + esym->st_size = size; |
1420 | + esym->st_other = other; |
1421 | + } |
1422 | + } else { |
1423 | + do_def: |
1424 | + sym_index = put_elf_sym(s, value, size, |
1425 | + ELFW(ST_INFO)(sym_bind, sym_type), other, |
1426 | + sh_num, name); |
1427 | + } |
1428 | + return sym_index; |
1429 | +} |
1430 | + |
1431 | +/* put relocation */ |
1432 | +ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, |
1433 | + int type, int symbol) |
1434 | +{ |
1435 | + char buf[256]; |
1436 | + Section *sr; |
1437 | + ElfW_Rel *rel; |
1438 | + |
1439 | + sr = s->reloc; |
1440 | + if (!sr) { |
1441 | + /* if no relocation section, create it */ |
1442 | + snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); |
1443 | + /* if the symtab is allocated, then we consider the relocation |
1444 | + are also */ |
1445 | + sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags); |
1446 | + sr->sh_entsize = sizeof(ElfW_Rel); |
1447 | + sr->link = symtab; |
1448 | + sr->sh_info = s->sh_num; |
1449 | + s->reloc = sr; |
1450 | + } |
1451 | + rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
1452 | + rel->r_offset = offset; |
1453 | + rel->r_info = ELFW(R_INFO)(symbol, type); |
1454 | +#ifdef TCC_TARGET_X86_64 |
1455 | + rel->r_addend = 0; |
1456 | +#endif |
1457 | +} |
1458 | + |
1459 | +/* put stab debug information */ |
1460 | + |
1461 | +ST_FUNC void put_stabs(const char *str, int type, int other, int desc, |
1462 | + unsigned long value) |
1463 | +{ |
1464 | + Stab_Sym *sym; |
1465 | + |
1466 | + sym = section_ptr_add(stab_section, sizeof(Stab_Sym)); |
1467 | + if (str) { |
1468 | + sym->n_strx = put_elf_str(stabstr_section, str); |
1469 | + } else { |
1470 | + sym->n_strx = 0; |
1471 | + } |
1472 | + sym->n_type = type; |
1473 | + sym->n_other = other; |
1474 | + sym->n_desc = desc; |
1475 | + sym->n_value = value; |
1476 | +} |
1477 | + |
1478 | +ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, |
1479 | + unsigned long value, Section *sec, int sym_index) |
1480 | +{ |
1481 | + put_stabs(str, type, other, desc, value); |
1482 | + put_elf_reloc(symtab_section, stab_section, |
1483 | + stab_section->data_offset - sizeof(unsigned int), |
1484 | + R_DATA_32, sym_index); |
1485 | +} |
1486 | + |
1487 | +ST_FUNC void put_stabn(int type, int other, int desc, int value) |
1488 | +{ |
1489 | + put_stabs(NULL, type, other, desc, value); |
1490 | +} |
1491 | + |
1492 | +ST_FUNC void put_stabd(int type, int other, int desc) |
1493 | +{ |
1494 | + put_stabs(NULL, type, other, desc, 0); |
1495 | +} |
1496 | + |
1497 | +/* In an ELF file symbol table, the local symbols must appear below |
1498 | + the global and weak ones. Since TCC cannot sort it while generating |
1499 | + the code, we must do it after. All the relocation tables are also |
1500 | + modified to take into account the symbol table sorting */ |
1501 | +static void sort_syms(TCCState *s1, Section *s) |
1502 | +{ |
1503 | + int *old_to_new_syms; |
1504 | + ElfW(Sym) *new_syms; |
1505 | + int nb_syms, i; |
1506 | + ElfW(Sym) *p, *q; |
1507 | + ElfW_Rel *rel, *rel_end; |
1508 | + Section *sr; |
1509 | + int type, sym_index; |
1510 | + |
1511 | + nb_syms = s->data_offset / sizeof(ElfW(Sym)); |
1512 | + new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym))); |
1513 | + old_to_new_syms = tcc_malloc(nb_syms * sizeof(int)); |
1514 | + |
1515 | + /* first pass for local symbols */ |
1516 | + p = (ElfW(Sym) *)s->data; |
1517 | + q = new_syms; |
1518 | + for(i = 0; i < nb_syms; i++) { |
1519 | + if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) { |
1520 | + old_to_new_syms[i] = q - new_syms; |
1521 | + *q++ = *p; |
1522 | + } |
1523 | + p++; |
1524 | + } |
1525 | + /* save the number of local symbols in section header */ |
1526 | + s->sh_info = q - new_syms; |
1527 | + |
1528 | + /* then second pass for non local symbols */ |
1529 | + p = (ElfW(Sym) *)s->data; |
1530 | + for(i = 0; i < nb_syms; i++) { |
1531 | + if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) { |
1532 | + old_to_new_syms[i] = q - new_syms; |
1533 | + *q++ = *p; |
1534 | + } |
1535 | + p++; |
1536 | + } |
1537 | + |
1538 | + /* we copy the new symbols to the old */ |
1539 | + memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym))); |
1540 | + tcc_free(new_syms); |
1541 | + |
1542 | + /* now we modify all the relocations */ |
1543 | + for(i = 1; i < s1->nb_sections; i++) { |
1544 | + sr = s1->sections[i]; |
1545 | + if (sr->sh_type == SHT_RELX && sr->link == s) { |
1546 | + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
1547 | + for(rel = (ElfW_Rel *)sr->data; |
1548 | + rel < rel_end; |
1549 | + rel++) { |
1550 | + sym_index = ELFW(R_SYM)(rel->r_info); |
1551 | + type = ELFW(R_TYPE)(rel->r_info); |
1552 | + sym_index = old_to_new_syms[sym_index]; |
1553 | + rel->r_info = ELFW(R_INFO)(sym_index, type); |
1554 | + } |
1555 | + } |
1556 | + } |
1557 | + |
1558 | + tcc_free(old_to_new_syms); |
1559 | +} |
1560 | + |
1561 | +/* relocate common symbols in the .bss section */ |
1562 | +ST_FUNC void relocate_common_syms(void) |
1563 | +{ |
1564 | + ElfW(Sym) *sym, *sym_end; |
1565 | + unsigned long offset, align; |
1566 | + |
1567 | + sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); |
1568 | + for(sym = (ElfW(Sym) *)symtab_section->data + 1; |
1569 | + sym < sym_end; |
1570 | + sym++) { |
1571 | + if (sym->st_shndx == SHN_COMMON) { |
1572 | + /* align symbol */ |
1573 | + align = sym->st_value; |
1574 | + offset = bss_section->data_offset; |
1575 | + offset = (offset + align - 1) & -align; |
1576 | + sym->st_value = offset; |
1577 | + sym->st_shndx = bss_section->sh_num; |
1578 | + offset += sym->st_size; |
1579 | + bss_section->data_offset = offset; |
1580 | + } |
1581 | + } |
1582 | +} |
1583 | + |
1584 | +/* relocate symbol table, resolve undefined symbols if do_resolve is |
1585 | + true and output error if undefined symbol. */ |
1586 | +ST_FUNC void relocate_syms(TCCState *s1, int do_resolve) |
1587 | +{ |
1588 | + ElfW(Sym) *sym, *esym, *sym_end; |
1589 | + int sym_bind, sh_num, sym_index; |
1590 | + const char *name; |
1591 | + |
1592 | + sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset); |
1593 | + for(sym = (ElfW(Sym) *)symtab_section->data + 1; |
1594 | + sym < sym_end; |
1595 | + sym++) { |
1596 | + sh_num = sym->st_shndx; |
1597 | + if (sh_num == SHN_UNDEF) { |
1598 | + name = strtab_section->data + sym->st_name; |
1599 | + if (do_resolve) { |
1600 | +#if !defined TCC_TARGET_PE || !defined _WIN32 |
1601 | + void *addr; |
1602 | + name = symtab_section->link->data + sym->st_name; |
1603 | + addr = resolve_sym(s1, name); |
1604 | + if (addr) { |
1605 | + sym->st_value = (uplong)addr; |
1606 | + goto found; |
1607 | + } |
1608 | +#endif |
1609 | + } else if (s1->dynsym) { |
1610 | + /* if dynamic symbol exist, then use it */ |
1611 | + sym_index = find_elf_sym(s1->dynsym, name); |
1612 | + if (sym_index) { |
1613 | + esym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index]; |
1614 | + sym->st_value = esym->st_value; |
1615 | + goto found; |
1616 | + } |
1617 | + } |
1618 | + /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
1619 | + it */ |
1620 | + if (!strcmp(name, "_fp_hw")) |
1621 | + goto found; |
1622 | + /* only weak symbols are accepted to be undefined. Their |
1623 | + value is zero */ |
1624 | + sym_bind = ELFW(ST_BIND)(sym->st_info); |
1625 | + if (sym_bind == STB_WEAK) { |
1626 | + sym->st_value = 0; |
1627 | + } else { |
1628 | + tcc_error_noabort("undefined symbol '%s'", name); |
1629 | + } |
1630 | + } else if (sh_num < SHN_LORESERVE) { |
1631 | + /* add section base */ |
1632 | + sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
1633 | + } |
1634 | + found: ; |
1635 | + } |
1636 | +} |
1637 | + |
1638 | +#ifndef TCC_TARGET_PE |
1639 | +#ifdef TCC_TARGET_X86_64 |
1640 | +#define JMP_TABLE_ENTRY_SIZE 14 |
1641 | +static uplong add_jmp_table(TCCState *s1, uplong val) |
1642 | +{ |
1643 | + char *p = s1->runtime_plt_and_got + s1->runtime_plt_and_got_offset; |
1644 | + s1->runtime_plt_and_got_offset += JMP_TABLE_ENTRY_SIZE; |
1645 | + /* jmp *0x0(%rip) */ |
1646 | + p[0] = 0xff; |
1647 | + p[1] = 0x25; |
1648 | + *(int *)(p + 2) = 0; |
1649 | + *(uplong *)(p + 6) = val; |
1650 | + return (uplong)p; |
1651 | +} |
1652 | + |
1653 | +static uplong add_got_table(TCCState *s1, uplong val) |
1654 | +{ |
1655 | + uplong *p = (uplong *)(s1->runtime_plt_and_got + s1->runtime_plt_and_got_offset); |
1656 | + s1->runtime_plt_and_got_offset += sizeof(uplong); |
1657 | + *p = val; |
1658 | + return (uplong)p; |
1659 | +} |
1660 | +#elif defined TCC_TARGET_ARM |
1661 | +#define JMP_TABLE_ENTRY_SIZE 8 |
1662 | +static uplong add_jmp_table(TCCState *s1, int val) |
1663 | +{ |
1664 | + uint32_t *p = (uint32_t *)(s1->runtime_plt_and_got + s1->runtime_plt_and_got_offset); |
1665 | + s1->runtime_plt_and_got_offset += JMP_TABLE_ENTRY_SIZE; |
1666 | + /* ldr pc, [pc, #-4] */ |
1667 | + p[0] = 0xE51FF004; |
1668 | + p[1] = val; |
1669 | + return (uplong)p; |
1670 | +} |
1671 | +#endif |
1672 | +#endif |
1673 | + |
1674 | +/* relocate a given section (CPU dependent) */ |
1675 | +ST_FUNC void relocate_section(TCCState *s1, Section *s) |
1676 | +{ |
1677 | + Section *sr; |
1678 | + ElfW_Rel *rel, *rel_end, *qrel; |
1679 | + ElfW(Sym) *sym; |
1680 | + int type, sym_index; |
1681 | + unsigned char *ptr; |
1682 | + uplong val, addr; |
1683 | +#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64 |
1684 | + int esym_index; |
1685 | +#endif |
1686 | + |
1687 | + sr = s->reloc; |
1688 | + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
1689 | + qrel = (ElfW_Rel *)sr->data; |
1690 | + for(rel = qrel; |
1691 | + rel < rel_end; |
1692 | + rel++) { |
1693 | + ptr = s->data + rel->r_offset; |
1694 | + |
1695 | + sym_index = ELFW(R_SYM)(rel->r_info); |
1696 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
1697 | + val = sym->st_value; |
1698 | +#ifdef TCC_TARGET_X86_64 |
1699 | + val += rel->r_addend; |
1700 | +#endif |
1701 | + type = ELFW(R_TYPE)(rel->r_info); |
1702 | + addr = s->sh_addr + rel->r_offset; |
1703 | + |
1704 | + /* CPU specific */ |
1705 | + switch(type) { |
1706 | +#if defined(TCC_TARGET_I386) |
1707 | + case R_386_32: |
1708 | + if (s1->output_type == TCC_OUTPUT_DLL) { |
1709 | + esym_index = s1->symtab_to_dynsym[sym_index]; |
1710 | + qrel->r_offset = rel->r_offset; |
1711 | + if (esym_index) { |
1712 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_32); |
1713 | + qrel++; |
1714 | + break; |
1715 | + } else { |
1716 | + qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE); |
1717 | + qrel++; |
1718 | + } |
1719 | + } |
1720 | + *(int *)ptr += val; |
1721 | + break; |
1722 | + case R_386_PC32: |
1723 | + if (s1->output_type == TCC_OUTPUT_DLL) { |
1724 | + /* DLL relocation */ |
1725 | + esym_index = s1->symtab_to_dynsym[sym_index]; |
1726 | + if (esym_index) { |
1727 | + qrel->r_offset = rel->r_offset; |
1728 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32); |
1729 | + qrel++; |
1730 | + break; |
1731 | + } |
1732 | + } |
1733 | + *(int *)ptr += val - addr; |
1734 | + break; |
1735 | + case R_386_PLT32: |
1736 | + *(int *)ptr += val - addr; |
1737 | + break; |
1738 | + case R_386_GLOB_DAT: |
1739 | + case R_386_JMP_SLOT: |
1740 | + *(int *)ptr = val; |
1741 | + break; |
1742 | + case R_386_GOTPC: |
1743 | + *(int *)ptr += s1->got->sh_addr - addr; |
1744 | + break; |
1745 | + case R_386_GOTOFF: |
1746 | + *(int *)ptr += val - s1->got->sh_addr; |
1747 | + break; |
1748 | + case R_386_GOT32: |
1749 | + /* we load the got offset */ |
1750 | + *(int *)ptr += s1->got_offsets[sym_index]; |
1751 | + break; |
1752 | + case R_386_16: |
1753 | + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { |
1754 | + output_file: |
1755 | + tcc_error("can only produce 16-bit binary files"); |
1756 | + } |
1757 | + *(short *)ptr += val; |
1758 | + break; |
1759 | + case R_386_PC16: |
1760 | + if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) |
1761 | + goto output_file; |
1762 | + *(short *)ptr += val - addr; |
1763 | + break; |
1764 | +#elif defined(TCC_TARGET_ARM) |
1765 | + case R_ARM_PC24: |
1766 | + case R_ARM_CALL: |
1767 | + case R_ARM_JUMP24: |
1768 | + case R_ARM_PLT32: |
1769 | + { |
1770 | + int x; |
1771 | + x = (*(int *)ptr)&0xffffff; |
1772 | + (*(int *)ptr) &= 0xff000000; |
1773 | + if (x & 0x800000) |
1774 | + x -= 0x1000000; |
1775 | + x *= 4; |
1776 | + x += val - addr; |
1777 | +#ifndef TCC_TARGET_PE |
1778 | + if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) |
1779 | + if (s1->output_type == TCC_OUTPUT_MEMORY) |
1780 | + x += add_jmp_table(s1, val) - val; /* add veneer */ |
1781 | +#endif |
1782 | + if((x & 3) != 0 || x >= 0x4000000 || x < -0x4000000) |
1783 | + tcc_error("can't relocate value at %x",addr); |
1784 | + x >>= 2; |
1785 | + x &= 0xffffff; |
1786 | + (*(int *)ptr) |= x; |
1787 | + } |
1788 | + break; |
1789 | + case R_ARM_PREL31: |
1790 | + { |
1791 | + int x; |
1792 | + x = (*(int *)ptr) & 0x7fffffff; |
1793 | + (*(int *)ptr) &= 0x80000000; |
1794 | + x = (x * 2) / 2; |
1795 | + x += val - addr; |
1796 | + if((x^(x>>1))&0x40000000) |
1797 | + tcc_error("can't relocate value at %x",addr); |
1798 | + (*(int *)ptr) |= x & 0x7fffffff; |
1799 | + } |
1800 | + case R_ARM_ABS32: |
1801 | + *(int *)ptr += val; |
1802 | + break; |
1803 | + case R_ARM_REL32: |
1804 | + *(int *)ptr += val - addr; |
1805 | + case R_ARM_BASE_PREL: |
1806 | + *(int *)ptr += s1->got->sh_addr - addr; |
1807 | + break; |
1808 | + case R_ARM_GOTOFF32: |
1809 | + *(int *)ptr += val - s1->got->sh_addr; |
1810 | + break; |
1811 | + case R_ARM_GOT_BREL: |
1812 | + /* we load the got offset */ |
1813 | + *(int *)ptr += s1->got_offsets[sym_index]; |
1814 | + break; |
1815 | + case R_ARM_COPY: |
1816 | + break; |
1817 | + case R_ARM_V4BX: |
1818 | + /* trade Thumb support for ARMv4 support */ |
1819 | + if ((0x0ffffff0 & *(int*)ptr) == 0x012FFF10) |
1820 | + *(int*)ptr ^= 0xE12FFF10 ^ 0xE1A0F000; /* BX Rm -> MOV PC, Rm */ |
1821 | + break; |
1822 | + default: |
1823 | + fprintf(stderr,"FIXME: handle reloc type %x at %x [%.8x] to %x\n", |
1824 | + type, (unsigned)addr, (unsigned)(uplong)ptr, (unsigned)val); |
1825 | + break; |
1826 | +#elif defined(TCC_TARGET_C67) |
1827 | + case R_C60_32: |
1828 | + *(int *)ptr += val; |
1829 | + break; |
1830 | + case R_C60LO16: |
1831 | + { |
1832 | + uint32_t orig; |
1833 | + |
1834 | + /* put the low 16 bits of the absolute address */ |
1835 | + // add to what is already there |
1836 | + |
1837 | + orig = ((*(int *)(ptr )) >> 7) & 0xffff; |
1838 | + orig |= (((*(int *)(ptr+4)) >> 7) & 0xffff) << 16; |
1839 | + |
1840 | + //patch both at once - assumes always in pairs Low - High |
1841 | + |
1842 | + *(int *) ptr = (*(int *) ptr & (~(0xffff << 7)) ) | (((val+orig) & 0xffff) << 7); |
1843 | + *(int *)(ptr+4) = (*(int *)(ptr+4) & (~(0xffff << 7)) ) | ((((val+orig)>>16) & 0xffff) << 7); |
1844 | + } |
1845 | + break; |
1846 | + case R_C60HI16: |
1847 | + break; |
1848 | + default: |
1849 | + fprintf(stderr,"FIXME: handle reloc type %x at %x [%.8x] to %x\n", |
1850 | + type, (unsigned)addr, (unsigned)(uplong)ptr, (unsigned)val); |
1851 | + break; |
1852 | +#elif defined(TCC_TARGET_X86_64) |
1853 | + case R_X86_64_64: |
1854 | + if (s1->output_type == TCC_OUTPUT_DLL) { |
1855 | + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
1856 | + qrel->r_addend = *(long long *)ptr + val; |
1857 | + qrel++; |
1858 | + } |
1859 | + *(long long *)ptr += val; |
1860 | + break; |
1861 | + case R_X86_64_32: |
1862 | + case R_X86_64_32S: |
1863 | + if (s1->output_type == TCC_OUTPUT_DLL) { |
1864 | + /* XXX: this logic may depend on TCC's codegen |
1865 | + now TCC uses R_X86_64_32 even for a 64bit pointer */ |
1866 | + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); |
1867 | + qrel->r_addend = *(int *)ptr + val; |
1868 | + qrel++; |
1869 | + } |
1870 | + *(int *)ptr += val; |
1871 | + break; |
1872 | + |
1873 | + case R_X86_64_PC32: |
1874 | + if (s1->output_type == TCC_OUTPUT_DLL) { |
1875 | + /* DLL relocation */ |
1876 | + esym_index = s1->symtab_to_dynsym[sym_index]; |
1877 | + if (esym_index) { |
1878 | + qrel->r_offset = rel->r_offset; |
1879 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32); |
1880 | + qrel->r_addend = *(int *)ptr; |
1881 | + qrel++; |
1882 | + break; |
1883 | + } |
1884 | + } |
1885 | + /* fall through */ |
1886 | + case R_X86_64_PLT32: { |
1887 | + long long diff; |
1888 | + diff = (long long)val - addr; |
1889 | + if (diff <= -2147483647 || diff > 2147483647) { |
1890 | +#ifndef TCC_TARGET_PE |
1891 | + /* XXX: naive support for over 32bit jump */ |
1892 | + if (s1->output_type == TCC_OUTPUT_MEMORY) { |
1893 | + val = (add_jmp_table(s1, val - rel->r_addend) + |
1894 | + rel->r_addend); |
1895 | + diff = val - addr; |
1896 | + } |
1897 | +#endif |
1898 | + if (diff <= -2147483647 || diff > 2147483647) { |
1899 | + tcc_error("internal error: relocation failed"); |
1900 | + } |
1901 | + } |
1902 | + *(int *)ptr += diff; |
1903 | + } |
1904 | + break; |
1905 | + case R_X86_64_GLOB_DAT: |
1906 | + case R_X86_64_JUMP_SLOT: |
1907 | + /* They don't need addend */ |
1908 | + *(int *)ptr = val - rel->r_addend; |
1909 | + break; |
1910 | + case R_X86_64_GOTPCREL: |
1911 | +#ifndef TCC_TARGET_PE |
1912 | + if (s1->output_type == TCC_OUTPUT_MEMORY) { |
1913 | + val = add_got_table(s1, val - rel->r_addend) + rel->r_addend; |
1914 | + *(int *)ptr += val - addr; |
1915 | + break; |
1916 | + } |
1917 | +#endif |
1918 | + *(int *)ptr += (s1->got->sh_addr - addr + |
1919 | + s1->got_offsets[sym_index] - 4); |
1920 | + break; |
1921 | + case R_X86_64_GOTTPOFF: |
1922 | + *(int *)ptr += val - s1->got->sh_addr; |
1923 | + break; |
1924 | + case R_X86_64_GOT32: |
1925 | + /* we load the got offset */ |
1926 | + *(int *)ptr += s1->got_offsets[sym_index]; |
1927 | + break; |
1928 | +#else |
1929 | +#error unsupported processor |
1930 | +#endif |
1931 | + } |
1932 | + } |
1933 | + /* if the relocation is allocated, we change its symbol table */ |
1934 | + if (sr->sh_flags & SHF_ALLOC) |
1935 | + sr->link = s1->dynsym; |
1936 | +} |
1937 | + |
1938 | +/* relocate relocation table in 'sr' */ |
1939 | +static void relocate_rel(TCCState *s1, Section *sr) |
1940 | +{ |
1941 | + Section *s; |
1942 | + ElfW_Rel *rel, *rel_end; |
1943 | + |
1944 | + s = s1->sections[sr->sh_info]; |
1945 | + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
1946 | + for(rel = (ElfW_Rel *)sr->data; |
1947 | + rel < rel_end; |
1948 | + rel++) { |
1949 | + rel->r_offset += s->sh_addr; |
1950 | + } |
1951 | +} |
1952 | + |
1953 | +/* count the number of dynamic relocations so that we can reserve |
1954 | + their space */ |
1955 | +static int prepare_dynamic_rel(TCCState *s1, Section *sr) |
1956 | +{ |
1957 | + ElfW_Rel *rel, *rel_end; |
1958 | + int sym_index, esym_index, type, count; |
1959 | + |
1960 | + count = 0; |
1961 | + rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
1962 | + for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { |
1963 | + sym_index = ELFW(R_SYM)(rel->r_info); |
1964 | + type = ELFW(R_TYPE)(rel->r_info); |
1965 | + switch(type) { |
1966 | +#if defined(TCC_TARGET_I386) |
1967 | + case R_386_32: |
1968 | +#elif defined(TCC_TARGET_X86_64) |
1969 | + case R_X86_64_32: |
1970 | + case R_X86_64_32S: |
1971 | + case R_X86_64_64: |
1972 | +#endif |
1973 | + count++; |
1974 | + break; |
1975 | +#if defined(TCC_TARGET_I386) |
1976 | + case R_386_PC32: |
1977 | +#elif defined(TCC_TARGET_X86_64) |
1978 | + case R_X86_64_PC32: |
1979 | +#endif |
1980 | + esym_index = s1->symtab_to_dynsym[sym_index]; |
1981 | + if (esym_index) |
1982 | + count++; |
1983 | + break; |
1984 | + default: |
1985 | + break; |
1986 | + } |
1987 | + } |
1988 | + if (count) { |
1989 | + /* allocate the section */ |
1990 | + sr->sh_flags |= SHF_ALLOC; |
1991 | + sr->sh_size = count * sizeof(ElfW_Rel); |
1992 | + } |
1993 | + return count; |
1994 | +} |
1995 | + |
1996 | +static void put_got_offset(TCCState *s1, int index, unsigned long val) |
1997 | +{ |
1998 | + int n; |
1999 | + unsigned long *tab; |
2000 | + |
2001 | + if (index >= s1->nb_got_offsets) { |
2002 | + /* find immediately bigger power of 2 and reallocate array */ |
2003 | + n = 1; |
2004 | + while (index >= n) |
2005 | + n *= 2; |
2006 | + tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long)); |
2007 | + s1->got_offsets = tab; |
2008 | + memset(s1->got_offsets + s1->nb_got_offsets, 0, |
2009 | + (n - s1->nb_got_offsets) * sizeof(unsigned long)); |
2010 | + s1->nb_got_offsets = n; |
2011 | + } |
2012 | + s1->got_offsets[index] = val; |
2013 | +} |
2014 | + |
2015 | +/* XXX: suppress that */ |
2016 | +static void put32(unsigned char *p, uint32_t val) |
2017 | +{ |
2018 | + p[0] = val; |
2019 | + p[1] = val >> 8; |
2020 | + p[2] = val >> 16; |
2021 | + p[3] = val >> 24; |
2022 | +} |
2023 | + |
2024 | +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_ARM) || \ |
2025 | + defined(TCC_TARGET_X86_64) |
2026 | +static uint32_t get32(unsigned char *p) |
2027 | +{ |
2028 | + return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); |
2029 | +} |
2030 | +#endif |
2031 | + |
2032 | +static void build_got(TCCState *s1) |
2033 | +{ |
2034 | + unsigned char *ptr; |
2035 | + |
2036 | + /* if no got, then create it */ |
2037 | + s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE); |
2038 | + s1->got->sh_entsize = 4; |
2039 | + add_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
2040 | + 0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_"); |
2041 | + ptr = section_ptr_add(s1->got, 3 * PTR_SIZE); |
2042 | +#if PTR_SIZE == 4 |
2043 | + /* keep space for _DYNAMIC pointer, if present */ |
2044 | + put32(ptr, 0); |
2045 | + /* two dummy got entries */ |
2046 | + put32(ptr + 4, 0); |
2047 | + put32(ptr + 8, 0); |
2048 | +#else |
2049 | + /* keep space for _DYNAMIC pointer, if present */ |
2050 | + put32(ptr, 0); |
2051 | + put32(ptr + 4, 0); |
2052 | + /* two dummy got entries */ |
2053 | + put32(ptr + 8, 0); |
2054 | + put32(ptr + 12, 0); |
2055 | + put32(ptr + 16, 0); |
2056 | + put32(ptr + 20, 0); |
2057 | +#endif |
2058 | +} |
2059 | + |
2060 | +/* put a got entry corresponding to a symbol in symtab_section. 'size' |
2061 | + and 'info' can be modifed if more precise info comes from the DLL */ |
2062 | +static void put_got_entry(TCCState *s1, |
2063 | + int reloc_type, unsigned long size, int info, |
2064 | + int sym_index) |
2065 | +{ |
2066 | + int index; |
2067 | + const char *name; |
2068 | + ElfW(Sym) *sym; |
2069 | + unsigned long offset; |
2070 | + int *ptr; |
2071 | + |
2072 | + if (!s1->got) |
2073 | + build_got(s1); |
2074 | + |
2075 | + /* if a got entry already exists for that symbol, no need to add one */ |
2076 | + if (sym_index < s1->nb_got_offsets && |
2077 | + s1->got_offsets[sym_index] != 0) |
2078 | + return; |
2079 | + |
2080 | + put_got_offset(s1, sym_index, s1->got->data_offset); |
2081 | + |
2082 | + if (s1->dynsym) { |
2083 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2084 | + name = symtab_section->link->data + sym->st_name; |
2085 | + offset = sym->st_value; |
2086 | +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) |
2087 | + if (reloc_type == |
2088 | +#ifdef TCC_TARGET_X86_64 |
2089 | + R_X86_64_JUMP_SLOT |
2090 | +#else |
2091 | + R_386_JMP_SLOT |
2092 | +#endif |
2093 | + ) { |
2094 | + Section *plt; |
2095 | + uint8_t *p; |
2096 | + int modrm; |
2097 | + |
2098 | +#if defined(TCC_OUTPUT_DLL_WITH_PLT) |
2099 | + modrm = 0x25; |
2100 | +#else |
2101 | + /* if we build a DLL, we add a %ebx offset */ |
2102 | + if (s1->output_type == TCC_OUTPUT_DLL) |
2103 | + modrm = 0xa3; |
2104 | + else |
2105 | + modrm = 0x25; |
2106 | +#endif |
2107 | + |
2108 | + /* add a PLT entry */ |
2109 | + plt = s1->plt; |
2110 | + if (plt->data_offset == 0) { |
2111 | + /* first plt entry */ |
2112 | + p = section_ptr_add(plt, 16); |
2113 | + p[0] = 0xff; /* pushl got + PTR_SIZE */ |
2114 | + p[1] = modrm + 0x10; |
2115 | + put32(p + 2, PTR_SIZE); |
2116 | + p[6] = 0xff; /* jmp *(got + PTR_SIZE * 2) */ |
2117 | + p[7] = modrm; |
2118 | + put32(p + 8, PTR_SIZE * 2); |
2119 | + } |
2120 | + |
2121 | + p = section_ptr_add(plt, 16); |
2122 | + p[0] = 0xff; /* jmp *(got + x) */ |
2123 | + p[1] = modrm; |
2124 | + put32(p + 2, s1->got->data_offset); |
2125 | + p[6] = 0x68; /* push $xxx */ |
2126 | + put32(p + 7, (plt->data_offset - 32) >> 1); |
2127 | + p[11] = 0xe9; /* jmp plt_start */ |
2128 | + put32(p + 12, -(plt->data_offset)); |
2129 | + |
2130 | + /* the symbol is modified so that it will be relocated to |
2131 | + the PLT */ |
2132 | +#if !defined(TCC_OUTPUT_DLL_WITH_PLT) |
2133 | + if (s1->output_type == TCC_OUTPUT_EXE) |
2134 | +#endif |
2135 | + offset = plt->data_offset - 16; |
2136 | + } |
2137 | +#elif defined(TCC_TARGET_ARM) |
2138 | + if (reloc_type == R_ARM_JUMP_SLOT) { |
2139 | + Section *plt; |
2140 | + uint8_t *p; |
2141 | + |
2142 | + /* if we build a DLL, we add a %ebx offset */ |
2143 | + if (s1->output_type == TCC_OUTPUT_DLL) |
2144 | + tcc_error("DLLs unimplemented!"); |
2145 | + |
2146 | + /* add a PLT entry */ |
2147 | + plt = s1->plt; |
2148 | + if (plt->data_offset == 0) { |
2149 | + /* first plt entry */ |
2150 | + p = section_ptr_add(plt, 16); |
2151 | + put32(p , 0xe52de004); |
2152 | + put32(p + 4, 0xe59fe010); |
2153 | + put32(p + 8, 0xe08fe00e); |
2154 | + put32(p + 12, 0xe5bef008); |
2155 | + } |
2156 | + |
2157 | + p = section_ptr_add(plt, 16); |
2158 | + put32(p , 0xe59fc004); |
2159 | + put32(p+4, 0xe08fc00c); |
2160 | + put32(p+8, 0xe59cf000); |
2161 | + put32(p+12, s1->got->data_offset); |
2162 | + |
2163 | + /* the symbol is modified so that it will be relocated to |
2164 | + the PLT */ |
2165 | + if (s1->output_type == TCC_OUTPUT_EXE) |
2166 | + offset = plt->data_offset - 16; |
2167 | + } |
2168 | +#elif defined(TCC_TARGET_C67) |
2169 | + tcc_error("C67 got not implemented"); |
2170 | +#else |
2171 | +#error unsupported CPU |
2172 | +#endif |
2173 | + index = put_elf_sym(s1->dynsym, offset, |
2174 | + size, info, 0, sym->st_shndx, name); |
2175 | + /* put a got entry */ |
2176 | + put_elf_reloc(s1->dynsym, s1->got, |
2177 | + s1->got->data_offset, |
2178 | + reloc_type, index); |
2179 | + } |
2180 | + ptr = section_ptr_add(s1->got, PTR_SIZE); |
2181 | + *ptr = 0; |
2182 | +} |
2183 | + |
2184 | +/* build GOT and PLT entries */ |
2185 | +ST_FUNC void build_got_entries(TCCState *s1) |
2186 | +{ |
2187 | + Section *s; |
2188 | + ElfW_Rel *rel, *rel_end; |
2189 | + ElfW(Sym) *sym; |
2190 | + int i, type, reloc_type, sym_index; |
2191 | + |
2192 | + for(i = 1; i < s1->nb_sections; i++) { |
2193 | + s = s1->sections[i]; |
2194 | + if (s->sh_type != SHT_RELX) |
2195 | + continue; |
2196 | + /* no need to handle got relocations */ |
2197 | + if (s->link != symtab_section) |
2198 | + continue; |
2199 | + rel_end = (ElfW_Rel *)(s->data + s->data_offset); |
2200 | + for(rel = (ElfW_Rel *)s->data; |
2201 | + rel < rel_end; |
2202 | + rel++) { |
2203 | + type = ELFW(R_TYPE)(rel->r_info); |
2204 | + switch(type) { |
2205 | +#if defined(TCC_TARGET_I386) |
2206 | + case R_386_GOT32: |
2207 | + case R_386_GOTOFF: |
2208 | + case R_386_GOTPC: |
2209 | + case R_386_PLT32: |
2210 | + if (!s1->got) |
2211 | + build_got(s1); |
2212 | + if (type == R_386_GOT32 || type == R_386_PLT32) { |
2213 | + sym_index = ELFW(R_SYM)(rel->r_info); |
2214 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2215 | + /* look at the symbol got offset. If none, then add one */ |
2216 | + if (type == R_386_GOT32) |
2217 | + reloc_type = R_386_GLOB_DAT; |
2218 | + else |
2219 | + reloc_type = R_386_JMP_SLOT; |
2220 | + put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
2221 | + sym_index); |
2222 | + } |
2223 | + break; |
2224 | +#elif defined(TCC_TARGET_ARM) |
2225 | + case R_ARM_GOT_BREL: |
2226 | + case R_ARM_GOTOFF32: |
2227 | + case R_ARM_BASE_PREL: |
2228 | + case R_ARM_PLT32: |
2229 | + if (!s1->got) |
2230 | + build_got(s1); |
2231 | + if (type == R_ARM_GOT_BREL || type == R_ARM_PLT32) { |
2232 | + sym_index = ELFW(R_SYM)(rel->r_info); |
2233 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2234 | + /* look at the symbol got offset. If none, then add one */ |
2235 | + if (type == R_ARM_GOT_BREL) |
2236 | + reloc_type = R_ARM_GLOB_DAT; |
2237 | + else |
2238 | + reloc_type = R_ARM_JUMP_SLOT; |
2239 | + put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
2240 | + sym_index); |
2241 | + } |
2242 | + break; |
2243 | +#elif defined(TCC_TARGET_C67) |
2244 | + case R_C60_GOT32: |
2245 | + case R_C60_GOTOFF: |
2246 | + case R_C60_GOTPC: |
2247 | + case R_C60_PLT32: |
2248 | + if (!s1->got) |
2249 | + build_got(s1); |
2250 | + if (type == R_C60_GOT32 || type == R_C60_PLT32) { |
2251 | + sym_index = ELFW(R_SYM)(rel->r_info); |
2252 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2253 | + /* look at the symbol got offset. If none, then add one */ |
2254 | + if (type == R_C60_GOT32) |
2255 | + reloc_type = R_C60_GLOB_DAT; |
2256 | + else |
2257 | + reloc_type = R_C60_JMP_SLOT; |
2258 | + put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
2259 | + sym_index); |
2260 | + } |
2261 | + break; |
2262 | +#elif defined(TCC_TARGET_X86_64) |
2263 | + case R_X86_64_GOT32: |
2264 | + case R_X86_64_GOTTPOFF: |
2265 | + case R_X86_64_GOTPCREL: |
2266 | + case R_X86_64_PLT32: |
2267 | + if (!s1->got) |
2268 | + build_got(s1); |
2269 | + if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || |
2270 | + type == R_X86_64_PLT32) { |
2271 | + sym_index = ELFW(R_SYM)(rel->r_info); |
2272 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2273 | + /* look at the symbol got offset. If none, then add one */ |
2274 | + if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL) |
2275 | + reloc_type = R_X86_64_GLOB_DAT; |
2276 | + else |
2277 | + reloc_type = R_X86_64_JUMP_SLOT; |
2278 | + put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
2279 | + sym_index); |
2280 | + } |
2281 | + break; |
2282 | +#else |
2283 | +#error unsupported CPU |
2284 | +#endif |
2285 | + default: |
2286 | + break; |
2287 | + } |
2288 | + } |
2289 | + } |
2290 | +} |
2291 | + |
2292 | +ST_FUNC Section *new_symtab(TCCState *s1, |
2293 | + const char *symtab_name, int sh_type, int sh_flags, |
2294 | + const char *strtab_name, |
2295 | + const char *hash_name, int hash_sh_flags) |
2296 | +{ |
2297 | + Section *symtab, *strtab, *hash; |
2298 | + int *ptr, nb_buckets; |
2299 | + |
2300 | + symtab = new_section(s1, symtab_name, sh_type, sh_flags); |
2301 | + symtab->sh_entsize = sizeof(ElfW(Sym)); |
2302 | + strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags); |
2303 | + put_elf_str(strtab, ""); |
2304 | + symtab->link = strtab; |
2305 | + put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL); |
2306 | + |
2307 | + nb_buckets = 1; |
2308 | + |
2309 | + hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags); |
2310 | + hash->sh_entsize = sizeof(int); |
2311 | + symtab->hash = hash; |
2312 | + hash->link = symtab; |
2313 | + |
2314 | + ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int)); |
2315 | + ptr[0] = nb_buckets; |
2316 | + ptr[1] = 1; |
2317 | + memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int)); |
2318 | + return symtab; |
2319 | +} |
2320 | + |
2321 | +/* put dynamic tag */ |
2322 | +static void put_dt(Section *dynamic, int dt, uplong val) |
2323 | +{ |
2324 | + ElfW(Dyn) *dyn; |
2325 | + dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn))); |
2326 | + dyn->d_tag = dt; |
2327 | + dyn->d_un.d_val = val; |
2328 | +} |
2329 | + |
2330 | +static void add_init_array_defines(TCCState *s1, const char *section_name) |
2331 | +{ |
2332 | + Section *s; |
2333 | + long end_offset; |
2334 | + char sym_start[1024]; |
2335 | + char sym_end[1024]; |
2336 | + |
2337 | + snprintf(sym_start, sizeof(sym_start), "__%s_start", section_name + 1); |
2338 | + snprintf(sym_end, sizeof(sym_end), "__%s_end", section_name + 1); |
2339 | + |
2340 | + s = find_section(s1, section_name); |
2341 | + if (!s) { |
2342 | + end_offset = 0; |
2343 | + s = data_section; |
2344 | + } else { |
2345 | + end_offset = s->data_offset; |
2346 | + } |
2347 | + |
2348 | + add_elf_sym(symtab_section, |
2349 | + 0, 0, |
2350 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2351 | + s->sh_num, sym_start); |
2352 | + add_elf_sym(symtab_section, |
2353 | + end_offset, 0, |
2354 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2355 | + s->sh_num, sym_end); |
2356 | +} |
2357 | + |
2358 | +static int tcc_add_support(TCCState *s1, const char *filename) |
2359 | +{ |
2360 | + char buf[1024]; |
2361 | + snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename); |
2362 | + return tcc_add_file(s1, buf); |
2363 | +} |
2364 | + |
2365 | +ST_FUNC void tcc_add_bcheck(TCCState *s1) |
2366 | +{ |
2367 | +#ifdef CONFIG_TCC_BCHECK |
2368 | + unsigned long *ptr; |
2369 | + Section *init_section; |
2370 | + unsigned char *pinit; |
2371 | + int sym_index; |
2372 | + |
2373 | + if (0 == s1->do_bounds_check) |
2374 | + return; |
2375 | + |
2376 | + /* XXX: add an object file to do that */ |
2377 | + ptr = section_ptr_add(bounds_section, sizeof(unsigned long)); |
2378 | + *ptr = 0; |
2379 | + add_elf_sym(symtab_section, 0, 0, |
2380 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2381 | + bounds_section->sh_num, "__bounds_start"); |
2382 | + /* add bound check code */ |
2383 | +#ifndef TCC_TARGET_PE |
2384 | + tcc_add_support(s1, "bcheck.o"); |
2385 | +#endif |
2386 | +#ifdef TCC_TARGET_I386 |
2387 | + if (s1->output_type != TCC_OUTPUT_MEMORY) { |
2388 | + /* add 'call __bound_init()' in .init section */ |
2389 | + init_section = find_section(s1, ".init"); |
2390 | + pinit = section_ptr_add(init_section, 5); |
2391 | + pinit[0] = 0xe8; |
2392 | + put32(pinit + 1, -4); |
2393 | + sym_index = find_elf_sym(symtab_section, "__bound_init"); |
2394 | + put_elf_reloc(symtab_section, init_section, |
2395 | + init_section->data_offset - 4, R_386_PC32, sym_index); |
2396 | + } |
2397 | +#endif |
2398 | +#endif |
2399 | +} |
2400 | + |
2401 | +/* add tcc runtime libraries */ |
2402 | +ST_FUNC void tcc_add_runtime(TCCState *s1) |
2403 | +{ |
2404 | + tcc_add_bcheck(s1); |
2405 | + |
2406 | + /* add libc */ |
2407 | + if (!s1->nostdlib) { |
2408 | + tcc_add_library(s1, "c"); |
2409 | +#ifdef CONFIG_USE_LIBGCC |
2410 | + tcc_add_file(s1, TCC_LIBGCC); |
2411 | +#elif !defined WITHOUT_LIBTCC |
2412 | + tcc_add_support(s1, "libtcc1.a"); |
2413 | +#endif |
2414 | + /* add crt end if not memory output */ |
2415 | + if (s1->output_type != TCC_OUTPUT_MEMORY) |
2416 | + tcc_add_crt(s1, "crtn.o"); |
2417 | + } |
2418 | +} |
2419 | + |
2420 | +/* add various standard linker symbols (must be done after the |
2421 | + sections are filled (for example after allocating common |
2422 | + symbols)) */ |
2423 | +ST_FUNC void tcc_add_linker_symbols(TCCState *s1) |
2424 | +{ |
2425 | + char buf[1024]; |
2426 | + int i; |
2427 | + Section *s; |
2428 | + |
2429 | + add_elf_sym(symtab_section, |
2430 | + text_section->data_offset, 0, |
2431 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2432 | + text_section->sh_num, "_etext"); |
2433 | + add_elf_sym(symtab_section, |
2434 | + data_section->data_offset, 0, |
2435 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2436 | + data_section->sh_num, "_edata"); |
2437 | + add_elf_sym(symtab_section, |
2438 | + bss_section->data_offset, 0, |
2439 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2440 | + bss_section->sh_num, "_end"); |
2441 | + /* horrible new standard ldscript defines */ |
2442 | + add_init_array_defines(s1, ".preinit_array"); |
2443 | + add_init_array_defines(s1, ".init_array"); |
2444 | + add_init_array_defines(s1, ".fini_array"); |
2445 | + |
2446 | + /* add start and stop symbols for sections whose name can be |
2447 | + expressed in C */ |
2448 | + for(i = 1; i < s1->nb_sections; i++) { |
2449 | + s = s1->sections[i]; |
2450 | + if (s->sh_type == SHT_PROGBITS && |
2451 | + (s->sh_flags & SHF_ALLOC)) { |
2452 | + const char *p; |
2453 | + int ch; |
2454 | + |
2455 | + /* check if section name can be expressed in C */ |
2456 | + p = s->name; |
2457 | + for(;;) { |
2458 | + ch = *p; |
2459 | + if (!ch) |
2460 | + break; |
2461 | + if (!isid(ch) && !isnum(ch)) |
2462 | + goto next_sec; |
2463 | + p++; |
2464 | + } |
2465 | + snprintf(buf, sizeof(buf), "__start_%s", s->name); |
2466 | + add_elf_sym(symtab_section, |
2467 | + 0, 0, |
2468 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2469 | + s->sh_num, buf); |
2470 | + snprintf(buf, sizeof(buf), "__stop_%s", s->name); |
2471 | + add_elf_sym(symtab_section, |
2472 | + s->data_offset, 0, |
2473 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
2474 | + s->sh_num, buf); |
2475 | + } |
2476 | + next_sec: ; |
2477 | + } |
2478 | +} |
2479 | + |
2480 | +static void tcc_output_binary(TCCState *s1, FILE *f, |
2481 | + const int *section_order) |
2482 | +{ |
2483 | + Section *s; |
2484 | + int i, offset, size; |
2485 | + |
2486 | + offset = 0; |
2487 | + for(i=1;i<s1->nb_sections;i++) { |
2488 | + s = s1->sections[section_order[i]]; |
2489 | + if (s->sh_type != SHT_NOBITS && |
2490 | + (s->sh_flags & SHF_ALLOC)) { |
2491 | + while (offset < s->sh_offset) { |
2492 | + fputc(0, f); |
2493 | + offset++; |
2494 | + } |
2495 | + size = s->sh_size; |
2496 | + fwrite(s->data, 1, size, f); |
2497 | + offset += size; |
2498 | + } |
2499 | + } |
2500 | +} |
2501 | + |
2502 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
2503 | +#define HAVE_PHDR 1 |
2504 | +#define EXTRA_RELITEMS 14 |
2505 | + |
2506 | +/* move the relocation value from .dynsym to .got */ |
2507 | +void patch_dynsym_undef(TCCState *s1, Section *s) |
2508 | +{ |
2509 | + uint32_t *gotd = (void *)s1->got->data; |
2510 | + ElfW(Sym) *sym, *sym_end; |
2511 | + |
2512 | + gotd += 3; // dummy entries in .got |
2513 | + /* relocate symbols in .dynsym */ |
2514 | + sym_end = (ElfW(Sym) *)(s->data + s->data_offset); |
2515 | + for (sym = (ElfW(Sym) *)s->data + 1; sym < sym_end; sym++) { |
2516 | + if (sym->st_shndx == SHN_UNDEF) { |
2517 | + *gotd++ = sym->st_value + 6; // XXX 6 is magic ? |
2518 | + sym->st_value = 0; |
2519 | + } |
2520 | + } |
2521 | +} |
2522 | +#else |
2523 | +#define HAVE_PHDR 0 |
2524 | +#define EXTRA_RELITEMS 9 |
2525 | + |
2526 | +/* zero plt offsets of weak symbols in .dynsym */ |
2527 | +void patch_dynsym_undef(TCCState *s1, Section *s) |
2528 | +{ |
2529 | + ElfW(Sym) *sym, *sym_end; |
2530 | + |
2531 | + sym_end = (ElfW(Sym) *)(s->data + s->data_offset); |
2532 | + for (sym = (ElfW(Sym) *)s->data + 1; sym < sym_end; sym++) |
2533 | + if (sym->st_shndx == SHN_UNDEF && ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
2534 | + sym->st_value = 0; |
2535 | +} |
2536 | +#endif |
2537 | + |
2538 | +ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) |
2539 | +{ |
2540 | + int sym_index = ELFW(R_SYM) (rel->r_info); |
2541 | + ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index]; |
2542 | + unsigned long offset; |
2543 | + |
2544 | + if (sym_index >= s1->nb_got_offsets) |
2545 | + return; |
2546 | + offset = s1->got_offsets[sym_index]; |
2547 | + section_reserve(s1->got, offset + PTR_SIZE); |
2548 | +#ifdef TCC_TARGET_X86_64 |
2549 | + /* only works for x86-64 */ |
2550 | + put32(s1->got->data + offset + 4, sym->st_value >> 32); |
2551 | +#endif |
2552 | + put32(s1->got->data + offset, sym->st_value & 0xffffffff); |
2553 | +} |
2554 | + |
2555 | +ST_FUNC void fill_got(TCCState *s1) |
2556 | +{ |
2557 | + Section *s; |
2558 | + ElfW_Rel *rel, *rel_end; |
2559 | + int i; |
2560 | + |
2561 | + for(i = 1; i < s1->nb_sections; i++) { |
2562 | + s = s1->sections[i]; |
2563 | + if (s->sh_type != SHT_RELX) |
2564 | + continue; |
2565 | + /* no need to handle got relocations */ |
2566 | + if (s->link != symtab_section) |
2567 | + continue; |
2568 | + rel_end = (ElfW_Rel *) (s->data + s->data_offset); |
2569 | + for(rel = (ElfW_Rel *) s->data; rel < rel_end; rel++) { |
2570 | + switch (ELFW(R_TYPE) (rel->r_info)) { |
2571 | + case R_X86_64_GOT32: |
2572 | + case R_X86_64_GOTPCREL: |
2573 | + case R_X86_64_PLT32: |
2574 | + fill_got_entry(s1, rel); |
2575 | + break; |
2576 | + } |
2577 | + } |
2578 | + } |
2579 | +} |
2580 | + |
2581 | + |
2582 | +/* output an ELF file */ |
2583 | +/* XXX: suppress unneeded sections */ |
2584 | +static int elf_output_file(TCCState *s1, const char *filename) |
2585 | +{ |
2586 | + ElfW(Ehdr) ehdr; |
2587 | + FILE *f; |
2588 | + int fd, mode, ret; |
2589 | + int *section_order; |
2590 | + int shnum, i, phnum, file_offset, offset, size, j, sh_order_index, k; |
2591 | + long long tmp; |
2592 | + uplong addr; |
2593 | + Section *strsec, *s; |
2594 | + ElfW(Shdr) shdr, *sh; |
2595 | + ElfW(Phdr) *phdr, *ph; |
2596 | + Section *interp, *dynamic, *dynstr; |
2597 | + unsigned long saved_dynamic_data_offset; |
2598 | + ElfW(Sym) *sym; |
2599 | + int type, file_type; |
2600 | + uplong rel_addr, rel_size; |
2601 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
2602 | + uplong bss_addr, bss_size; |
2603 | +#endif |
2604 | + |
2605 | + file_type = s1->output_type; |
2606 | + s1->nb_errors = 0; |
2607 | + |
2608 | + if (file_type != TCC_OUTPUT_OBJ) { |
2609 | + tcc_add_runtime(s1); |
2610 | + } |
2611 | + |
2612 | + phdr = NULL; |
2613 | + section_order = NULL; |
2614 | + interp = NULL; |
2615 | + dynamic = NULL; |
2616 | + dynstr = NULL; /* avoid warning */ |
2617 | + saved_dynamic_data_offset = 0; /* avoid warning */ |
2618 | + |
2619 | + if (file_type != TCC_OUTPUT_OBJ) { |
2620 | + relocate_common_syms(); |
2621 | + |
2622 | + tcc_add_linker_symbols(s1); |
2623 | + |
2624 | + if (!s1->static_link) { |
2625 | + const char *name; |
2626 | + int sym_index, index; |
2627 | + ElfW(Sym) *esym, *sym_end; |
2628 | + |
2629 | + if (file_type == TCC_OUTPUT_EXE) { |
2630 | + char *ptr; |
2631 | + /* allow override the dynamic loader */ |
2632 | + const char *elfint = getenv("LD_SO"); |
2633 | + if (elfint == NULL) |
2634 | + elfint = CONFIG_TCC_ELFINTERP; |
2635 | + /* add interpreter section only if executable */ |
2636 | + interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); |
2637 | + interp->sh_addralign = 1; |
2638 | + ptr = section_ptr_add(interp, 1+strlen(elfint)); |
2639 | + strcpy(ptr, elfint); |
2640 | + } |
2641 | + |
2642 | + /* add dynamic symbol table */ |
2643 | + s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
2644 | + ".dynstr", |
2645 | + ".hash", SHF_ALLOC); |
2646 | + dynstr = s1->dynsym->link; |
2647 | + |
2648 | + /* add dynamic section */ |
2649 | + dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC, |
2650 | + SHF_ALLOC | SHF_WRITE); |
2651 | + dynamic->link = dynstr; |
2652 | + dynamic->sh_entsize = sizeof(ElfW(Dyn)); |
2653 | + |
2654 | + /* add PLT */ |
2655 | + s1->plt = new_section(s1, ".plt", SHT_PROGBITS, |
2656 | + SHF_ALLOC | SHF_EXECINSTR); |
2657 | + s1->plt->sh_entsize = 4; |
2658 | + |
2659 | + build_got(s1); |
2660 | + |
2661 | + /* scan for undefined symbols and see if they are in the |
2662 | + dynamic symbols. If a symbol STT_FUNC or STT_GNU_IFUNC |
2663 | + is found, then we add it in the PLT. If a symbol |
2664 | + STT_OBJECT is found, we add it in the .bss section with |
2665 | + a suitable relocation */ |
2666 | + sym_end = (ElfW(Sym) *)(symtab_section->data + |
2667 | + symtab_section->data_offset); |
2668 | + if (file_type == TCC_OUTPUT_EXE) { |
2669 | + for(sym = (ElfW(Sym) *)symtab_section->data + 1; |
2670 | + sym < sym_end; |
2671 | + sym++) { |
2672 | + if (sym->st_shndx == SHN_UNDEF) { |
2673 | + name = symtab_section->link->data + sym->st_name; |
2674 | + sym_index = find_elf_sym(s1->dynsymtab_section, name); |
2675 | + if (sym_index) { |
2676 | + esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index]; |
2677 | + type = ELFW(ST_TYPE)(esym->st_info); |
2678 | + if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) { |
2679 | + put_got_entry(s1, R_JMP_SLOT, esym->st_size, |
2680 | + ELFW(ST_INFO)(STB_GLOBAL,type), |
2681 | + sym - (ElfW(Sym) *)symtab_section->data); |
2682 | + } else if (type == STT_OBJECT) { |
2683 | + unsigned long offset; |
2684 | + ElfW(Sym) *dynsym, *dynsym_end; |
2685 | + offset = bss_section->data_offset; |
2686 | + /* XXX: which alignment ? */ |
2687 | + offset = (offset + 16 - 1) & -16; |
2688 | + index = put_elf_sym(s1->dynsym, offset, esym->st_size, |
2689 | + esym->st_info, 0, |
2690 | + bss_section->sh_num, name); |
2691 | + // Ensure R_COPY works for weak symbol aliases |
2692 | + if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { |
2693 | + dynsym_end = (ElfW(Sym) *) |
2694 | + (s1->dynsymtab_section->data + |
2695 | + s1->dynsymtab_section->data_offset); |
2696 | + for(dynsym = (ElfW(Sym) *)s1->dynsymtab_section->data + 1; |
2697 | + dynsym < dynsym_end; dynsym++) { |
2698 | + if ((dynsym->st_value == esym->st_value) |
2699 | + && (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) { |
2700 | + char *dynname; |
2701 | + dynname = s1->dynsymtab_section->link->data |
2702 | + + dynsym->st_name; |
2703 | + put_elf_sym(s1->dynsym, offset, |
2704 | + dynsym->st_size, |
2705 | + dynsym->st_info, 0, |
2706 | + bss_section->sh_num, |
2707 | + dynname); |
2708 | + break; |
2709 | + } |
2710 | + } |
2711 | + } |
2712 | + put_elf_reloc(s1->dynsym, bss_section, |
2713 | + offset, R_COPY, index); |
2714 | + offset += esym->st_size; |
2715 | + bss_section->data_offset = offset; |
2716 | + } |
2717 | + } else { |
2718 | + /* STB_WEAK undefined symbols are accepted */ |
2719 | + /* XXX: _fp_hw seems to be part of the ABI, so we ignore |
2720 | + it */ |
2721 | + if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK || |
2722 | + !strcmp(name, "_fp_hw")) { |
2723 | + } else { |
2724 | + tcc_error_noabort("undefined symbol '%s'", name); |
2725 | + } |
2726 | + } |
2727 | + } else if (s1->rdynamic && |
2728 | + ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
2729 | + /* if -rdynamic option, then export all non |
2730 | + local symbols */ |
2731 | + name = symtab_section->link->data + sym->st_name; |
2732 | + put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
2733 | + sym->st_info, 0, |
2734 | + sym->st_shndx, name); |
2735 | + } |
2736 | + } |
2737 | + |
2738 | + if (s1->nb_errors) |
2739 | + goto fail; |
2740 | + |
2741 | + /* now look at unresolved dynamic symbols and export |
2742 | + corresponding symbol */ |
2743 | + sym_end = (ElfW(Sym) *)(s1->dynsymtab_section->data + |
2744 | + s1->dynsymtab_section->data_offset); |
2745 | + for(esym = (ElfW(Sym) *)s1->dynsymtab_section->data + 1; |
2746 | + esym < sym_end; |
2747 | + esym++) { |
2748 | + if (esym->st_shndx == SHN_UNDEF) { |
2749 | + name = s1->dynsymtab_section->link->data + esym->st_name; |
2750 | + sym_index = find_elf_sym(symtab_section, name); |
2751 | + if (sym_index) { |
2752 | + /* XXX: avoid adding a symbol if already |
2753 | + present because of -rdynamic ? */ |
2754 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
2755 | + put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
2756 | + sym->st_info, 0, |
2757 | + sym->st_shndx, name); |
2758 | + } else { |
2759 | + if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) { |
2760 | + /* weak symbols can stay undefined */ |
2761 | + } else { |
2762 | + tcc_warning("undefined dynamic symbol '%s'", name); |
2763 | + } |
2764 | + } |
2765 | + } |
2766 | + } |
2767 | + } else { |
2768 | + int nb_syms; |
2769 | + /* shared library case : we simply export all the global symbols */ |
2770 | + nb_syms = symtab_section->data_offset / sizeof(ElfW(Sym)); |
2771 | + s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
2772 | + for(sym = (ElfW(Sym) *)symtab_section->data + 1; |
2773 | + sym < sym_end; |
2774 | + sym++) { |
2775 | + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
2776 | +#if defined(TCC_OUTPUT_DLL_WITH_PLT) |
2777 | + if ((ELFW(ST_TYPE)(sym->st_info) == STT_FUNC || |
2778 | + ELFW(ST_TYPE)(sym->st_info) == STT_GNU_IFUNC) |
2779 | + && sym->st_shndx == SHN_UNDEF) { |
2780 | + put_got_entry(s1, R_JMP_SLOT, sym->st_size, |
2781 | + sym->st_info, |
2782 | + sym - (ElfW(Sym) *)symtab_section->data); |
2783 | + } |
2784 | + else if (ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT) { |
2785 | + put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, |
2786 | + sym->st_info, |
2787 | + sym - (ElfW(Sym) *)symtab_section->data); |
2788 | + } |
2789 | + else |
2790 | +#endif |
2791 | + { |
2792 | + name = symtab_section->link->data + sym->st_name; |
2793 | + index = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
2794 | + sym->st_info, 0, |
2795 | + sym->st_shndx, name); |
2796 | + s1->symtab_to_dynsym[sym - |
2797 | + (ElfW(Sym) *)symtab_section->data] = |
2798 | + index; |
2799 | + } |
2800 | + } |
2801 | + } |
2802 | + } |
2803 | + |
2804 | + build_got_entries(s1); |
2805 | + |
2806 | + /* add a list of needed dlls */ |
2807 | + for(i = 0; i < s1->nb_loaded_dlls; i++) { |
2808 | + DLLReference *dllref = s1->loaded_dlls[i]; |
2809 | + if (dllref->level == 0) |
2810 | + put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name)); |
2811 | + } |
2812 | + |
2813 | + if (s1->rpath) |
2814 | + put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath)); |
2815 | + |
2816 | + /* XXX: currently, since we do not handle PIC code, we |
2817 | + must relocate the readonly segments */ |
2818 | + if (file_type == TCC_OUTPUT_DLL) { |
2819 | + if (s1->soname) |
2820 | + put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); |
2821 | + put_dt(dynamic, DT_TEXTREL, 0); |
2822 | + } |
2823 | + |
2824 | + if (s1->symbolic) |
2825 | + put_dt(dynamic, DT_SYMBOLIC, 0); |
2826 | + |
2827 | + /* add necessary space for other entries */ |
2828 | + saved_dynamic_data_offset = dynamic->data_offset; |
2829 | + dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; |
2830 | + } else { |
2831 | + /* still need to build got entries in case of static link */ |
2832 | + build_got_entries(s1); |
2833 | + } |
2834 | + } |
2835 | + |
2836 | + memset(&ehdr, 0, sizeof(ehdr)); |
2837 | + |
2838 | + /* we add a section for symbols */ |
2839 | + strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0); |
2840 | + put_elf_str(strsec, ""); |
2841 | + |
2842 | + /* compute number of sections */ |
2843 | + shnum = s1->nb_sections; |
2844 | + |
2845 | + /* this array is used to reorder sections in the output file */ |
2846 | + section_order = tcc_malloc(sizeof(int) * shnum); |
2847 | + section_order[0] = 0; |
2848 | + sh_order_index = 1; |
2849 | + |
2850 | + /* compute number of program headers */ |
2851 | + switch(file_type) { |
2852 | + default: |
2853 | + case TCC_OUTPUT_OBJ: |
2854 | + phnum = 0; |
2855 | + break; |
2856 | + case TCC_OUTPUT_EXE: |
2857 | + if (!s1->static_link) |
2858 | + phnum = 4 + HAVE_PHDR; |
2859 | + else |
2860 | + phnum = 2; |
2861 | + break; |
2862 | + case TCC_OUTPUT_DLL: |
2863 | + phnum = 3; |
2864 | + break; |
2865 | + } |
2866 | + |
2867 | + /* allocate strings for section names and decide if an unallocated |
2868 | + section should be output */ |
2869 | + /* NOTE: the strsec section comes last, so its size is also |
2870 | + correct ! */ |
2871 | + for(i = 1; i < s1->nb_sections; i++) { |
2872 | + s = s1->sections[i]; |
2873 | + s->sh_name = put_elf_str(strsec, s->name); |
2874 | +#if 0 //gr |
2875 | + printf("section: f=%08x t=%08x i=%08x %s %s\n", |
2876 | + s->sh_flags, |
2877 | + s->sh_type, |
2878 | + s->sh_info, |
2879 | + s->name, |
2880 | + s->reloc ? s->reloc->name : "n" |
2881 | + ); |
2882 | +#endif |
2883 | + /* when generating a DLL, we include relocations but we may |
2884 | + patch them */ |
2885 | + if (file_type == TCC_OUTPUT_DLL && |
2886 | + s->sh_type == SHT_RELX && |
2887 | + !(s->sh_flags & SHF_ALLOC)) { |
2888 | + /* //gr: avoid bogus relocs for empty (debug) sections */ |
2889 | + if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) |
2890 | + prepare_dynamic_rel(s1, s); |
2891 | + else if (s1->do_debug) |
2892 | + s->sh_size = s->data_offset; |
2893 | + } else if (s1->do_debug || |
2894 | + file_type == TCC_OUTPUT_OBJ || |
2895 | + (s->sh_flags & SHF_ALLOC) || |
2896 | + i == (s1->nb_sections - 1)) { |
2897 | + /* we output all sections if debug or object file */ |
2898 | + s->sh_size = s->data_offset; |
2899 | + } |
2900 | + } |
2901 | + |
2902 | + /* allocate program segment headers */ |
2903 | + phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); |
2904 | + |
2905 | + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
2906 | + file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
2907 | + } else { |
2908 | + file_offset = 0; |
2909 | + } |
2910 | + if (phnum > 0) { |
2911 | + /* compute section to program header mapping */ |
2912 | + if (s1->has_text_addr) { |
2913 | + int a_offset, p_offset; |
2914 | + addr = s1->text_addr; |
2915 | + /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % |
2916 | + ELF_PAGE_SIZE */ |
2917 | + a_offset = (int) (addr & (s1->section_align - 1)); |
2918 | + p_offset = file_offset & (s1->section_align - 1); |
2919 | + if (a_offset < p_offset) |
2920 | + a_offset += s1->section_align; |
2921 | + file_offset += (a_offset - p_offset); |
2922 | + } else { |
2923 | + if (file_type == TCC_OUTPUT_DLL) |
2924 | + addr = 0; |
2925 | + else |
2926 | + addr = ELF_START_ADDR; |
2927 | + /* compute address after headers */ |
2928 | + addr += (file_offset & (s1->section_align - 1)); |
2929 | + } |
2930 | + |
2931 | + /* dynamic relocation table information, for .dynamic section */ |
2932 | + rel_size = 0; |
2933 | + rel_addr = 0; |
2934 | + |
2935 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
2936 | + bss_addr = bss_size = 0; |
2937 | +#endif |
2938 | + /* leave one program header for the program interpreter */ |
2939 | + ph = &phdr[0]; |
2940 | + if (interp) |
2941 | + ph += 1 + HAVE_PHDR; |
2942 | + |
2943 | + for(j = 0; j < 2; j++) { |
2944 | + ph->p_type = PT_LOAD; |
2945 | + if (j == 0) |
2946 | + ph->p_flags = PF_R | PF_X; |
2947 | + else |
2948 | + ph->p_flags = PF_R | PF_W; |
2949 | + ph->p_align = s1->section_align; |
2950 | + |
2951 | + /* we do the following ordering: interp, symbol tables, |
2952 | + relocations, progbits, nobits */ |
2953 | + /* XXX: do faster and simpler sorting */ |
2954 | + for(k = 0; k < 5; k++) { |
2955 | + for(i = 1; i < s1->nb_sections; i++) { |
2956 | + s = s1->sections[i]; |
2957 | + /* compute if section should be included */ |
2958 | + if (j == 0) { |
2959 | + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != |
2960 | + SHF_ALLOC) |
2961 | + continue; |
2962 | + } else { |
2963 | + if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) != |
2964 | + (SHF_ALLOC | SHF_WRITE)) |
2965 | + continue; |
2966 | + } |
2967 | + if (s == interp) { |
2968 | + if (k != 0) |
2969 | + continue; |
2970 | + } else if (s->sh_type == SHT_DYNSYM || |
2971 | + s->sh_type == SHT_STRTAB || |
2972 | + s->sh_type == SHT_HASH) { |
2973 | + if (k != 1) |
2974 | + continue; |
2975 | + } else if (s->sh_type == SHT_RELX) { |
2976 | + if (k != 2) |
2977 | + continue; |
2978 | + } else if (s->sh_type == SHT_NOBITS) { |
2979 | + if (k != 4) |
2980 | + continue; |
2981 | + } else { |
2982 | + if (k != 3) |
2983 | + continue; |
2984 | + } |
2985 | + section_order[sh_order_index++] = i; |
2986 | + |
2987 | + /* section matches: we align it and add its size */ |
2988 | + tmp = addr; |
2989 | + addr = (addr + s->sh_addralign - 1) & |
2990 | + ~(s->sh_addralign - 1); |
2991 | + file_offset += (int) ( addr - tmp ); |
2992 | + s->sh_offset = file_offset; |
2993 | + s->sh_addr = addr; |
2994 | + |
2995 | + /* update program header infos */ |
2996 | + if (ph->p_offset == 0) { |
2997 | + ph->p_offset = file_offset; |
2998 | + ph->p_vaddr = addr; |
2999 | + ph->p_paddr = ph->p_vaddr; |
3000 | + } |
3001 | + /* update dynamic relocation infos */ |
3002 | + if (s->sh_type == SHT_RELX) { |
3003 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
3004 | + if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { // rel_size == 0) { |
3005 | + rel_addr = addr; |
3006 | + rel_size += s->sh_size; // XXX only first rel. |
3007 | + } |
3008 | + if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { // rel_size == 0) { |
3009 | + bss_addr = addr; |
3010 | + bss_size = s->sh_size; // XXX only first rel. |
3011 | + } |
3012 | +#else |
3013 | + if (rel_size == 0) |
3014 | + rel_addr = addr; |
3015 | + rel_size += s->sh_size; |
3016 | +#endif |
3017 | + } |
3018 | + addr += s->sh_size; |
3019 | + if (s->sh_type != SHT_NOBITS) |
3020 | + file_offset += s->sh_size; |
3021 | + } |
3022 | + } |
3023 | + ph->p_filesz = file_offset - ph->p_offset; |
3024 | + ph->p_memsz = addr - ph->p_vaddr; |
3025 | + ph++; |
3026 | + if (j == 0) { |
3027 | + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
3028 | + /* if in the middle of a page, we duplicate the page in |
3029 | + memory so that one copy is RX and the other is RW */ |
3030 | + if ((addr & (s1->section_align - 1)) != 0) |
3031 | + addr += s1->section_align; |
3032 | + } else { |
3033 | + addr = (addr + s1->section_align - 1) & ~(s1->section_align - 1); |
3034 | + file_offset = (file_offset + s1->section_align - 1) & |
3035 | + ~(s1->section_align - 1); |
3036 | + } |
3037 | + } |
3038 | + } |
3039 | + |
3040 | + /* if interpreter, then add corresponing program header */ |
3041 | + if (interp) { |
3042 | + ph = &phdr[0]; |
3043 | + |
3044 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
3045 | + { |
3046 | + int len = phnum * sizeof(ElfW(Phdr)); |
3047 | + |
3048 | + ph->p_type = PT_PHDR; |
3049 | + ph->p_offset = sizeof(ElfW(Ehdr)); |
3050 | + ph->p_vaddr = interp->sh_addr - len; |
3051 | + ph->p_paddr = ph->p_vaddr; |
3052 | + ph->p_filesz = ph->p_memsz = len; |
3053 | + ph->p_flags = PF_R | PF_X; |
3054 | + ph->p_align = 4; // interp->sh_addralign; |
3055 | + ph++; |
3056 | + } |
3057 | +#endif |
3058 | + |
3059 | + ph->p_type = PT_INTERP; |
3060 | + ph->p_offset = interp->sh_offset; |
3061 | + ph->p_vaddr = interp->sh_addr; |
3062 | + ph->p_paddr = ph->p_vaddr; |
3063 | + ph->p_filesz = interp->sh_size; |
3064 | + ph->p_memsz = interp->sh_size; |
3065 | + ph->p_flags = PF_R; |
3066 | + ph->p_align = interp->sh_addralign; |
3067 | + } |
3068 | + |
3069 | + /* if dynamic section, then add corresponing program header */ |
3070 | + if (dynamic) { |
3071 | + ElfW(Sym) *sym_end; |
3072 | + |
3073 | + ph = &phdr[phnum - 1]; |
3074 | + |
3075 | + ph->p_type = PT_DYNAMIC; |
3076 | + ph->p_offset = dynamic->sh_offset; |
3077 | + ph->p_vaddr = dynamic->sh_addr; |
3078 | + ph->p_paddr = ph->p_vaddr; |
3079 | + ph->p_filesz = dynamic->sh_size; |
3080 | + ph->p_memsz = dynamic->sh_size; |
3081 | + ph->p_flags = PF_R | PF_W; |
3082 | + ph->p_align = dynamic->sh_addralign; |
3083 | + |
3084 | + /* put GOT dynamic section address */ |
3085 | + put32(s1->got->data, dynamic->sh_addr); |
3086 | + |
3087 | + /* relocate the PLT */ |
3088 | + if (file_type == TCC_OUTPUT_EXE |
3089 | +#if defined(TCC_OUTPUT_DLL_WITH_PLT) |
3090 | + || file_type == TCC_OUTPUT_DLL |
3091 | +#endif |
3092 | + ) { |
3093 | + uint8_t *p, *p_end; |
3094 | + |
3095 | + p = s1->plt->data; |
3096 | + p_end = p + s1->plt->data_offset; |
3097 | + if (p < p_end) { |
3098 | +#if defined(TCC_TARGET_I386) |
3099 | + put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
3100 | + put32(p + 8, get32(p + 8) + s1->got->sh_addr); |
3101 | + p += 16; |
3102 | + while (p < p_end) { |
3103 | + put32(p + 2, get32(p + 2) + s1->got->sh_addr); |
3104 | + p += 16; |
3105 | + } |
3106 | +#elif defined(TCC_TARGET_X86_64) |
3107 | + int x = s1->got->sh_addr - s1->plt->sh_addr - 6; |
3108 | + put32(p + 2, get32(p + 2) + x); |
3109 | + put32(p + 8, get32(p + 8) + x - 6); |
3110 | + p += 16; |
3111 | + while (p < p_end) { |
3112 | + put32(p + 2, get32(p + 2) + x + s1->plt->data - p); |
3113 | + p += 16; |
3114 | + } |
3115 | +#elif defined(TCC_TARGET_ARM) |
3116 | + int x; |
3117 | + x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
3118 | + p +=16; |
3119 | + while (p < p_end) { |
3120 | + put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
3121 | + p += 16; |
3122 | + } |
3123 | +#elif defined(TCC_TARGET_C67) |
3124 | + /* XXX: TODO */ |
3125 | +#else |
3126 | +#error unsupported CPU |
3127 | +#endif |
3128 | + } |
3129 | + } |
3130 | + |
3131 | + /* relocate symbols in .dynsym */ |
3132 | + sym_end = (ElfW(Sym) *)(s1->dynsym->data + s1->dynsym->data_offset); |
3133 | + for(sym = (ElfW(Sym) *)s1->dynsym->data + 1; |
3134 | + sym < sym_end; |
3135 | + sym++) { |
3136 | + if (sym->st_shndx == SHN_UNDEF) { |
3137 | + /* relocate to the PLT if the symbol corresponds |
3138 | + to a PLT entry */ |
3139 | + if (sym->st_value) |
3140 | + sym->st_value += s1->plt->sh_addr; |
3141 | + } else if (sym->st_shndx < SHN_LORESERVE) { |
3142 | + /* do symbol relocation */ |
3143 | + sym->st_value += s1->sections[sym->st_shndx]->sh_addr; |
3144 | + } |
3145 | + } |
3146 | + |
3147 | + /* put dynamic section entries */ |
3148 | + dynamic->data_offset = saved_dynamic_data_offset; |
3149 | + put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr); |
3150 | + put_dt(dynamic, DT_STRTAB, dynstr->sh_addr); |
3151 | + put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr); |
3152 | + put_dt(dynamic, DT_STRSZ, dynstr->data_offset); |
3153 | + put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym))); |
3154 | +#ifdef TCC_TARGET_X86_64 |
3155 | + put_dt(dynamic, DT_RELA, rel_addr); |
3156 | + put_dt(dynamic, DT_RELASZ, rel_size); |
3157 | + put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
3158 | +#else |
3159 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
3160 | + put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
3161 | + put_dt(dynamic, DT_PLTRELSZ, rel_size); |
3162 | + put_dt(dynamic, DT_JMPREL, rel_addr); |
3163 | + put_dt(dynamic, DT_PLTREL, DT_REL); |
3164 | + put_dt(dynamic, DT_REL, bss_addr); |
3165 | + put_dt(dynamic, DT_RELSZ, bss_size); |
3166 | +#else |
3167 | + put_dt(dynamic, DT_REL, rel_addr); |
3168 | + put_dt(dynamic, DT_RELSZ, rel_size); |
3169 | + put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
3170 | +#endif |
3171 | +#endif |
3172 | + if (s1->do_debug) |
3173 | + put_dt(dynamic, DT_DEBUG, 0); |
3174 | + put_dt(dynamic, DT_NULL, 0); |
3175 | + } |
3176 | + |
3177 | + ehdr.e_phentsize = sizeof(ElfW(Phdr)); |
3178 | + ehdr.e_phnum = phnum; |
3179 | + ehdr.e_phoff = sizeof(ElfW(Ehdr)); |
3180 | + } |
3181 | + |
3182 | + /* all other sections come after */ |
3183 | + for(i = 1; i < s1->nb_sections; i++) { |
3184 | + s = s1->sections[i]; |
3185 | + if (phnum > 0 && (s->sh_flags & SHF_ALLOC)) |
3186 | + continue; |
3187 | + section_order[sh_order_index++] = i; |
3188 | + |
3189 | + file_offset = (file_offset + s->sh_addralign - 1) & |
3190 | + ~(s->sh_addralign - 1); |
3191 | + s->sh_offset = file_offset; |
3192 | + if (s->sh_type != SHT_NOBITS) |
3193 | + file_offset += s->sh_size; |
3194 | + } |
3195 | + |
3196 | + /* if building executable or DLL, then relocate each section |
3197 | + except the GOT which is already relocated */ |
3198 | + if (file_type != TCC_OUTPUT_OBJ) { |
3199 | + relocate_syms(s1, 0); |
3200 | + |
3201 | + if (s1->nb_errors != 0) { |
3202 | + fail: |
3203 | + ret = -1; |
3204 | + goto the_end; |
3205 | + } |
3206 | + |
3207 | + /* relocate sections */ |
3208 | + /* XXX: ignore sections with allocated relocations ? */ |
3209 | + for(i = 1; i < s1->nb_sections; i++) { |
3210 | + s = s1->sections[i]; |
3211 | + if (s->reloc && s != s1->got && (s->sh_flags & SHF_ALLOC)) //gr |
3212 | + relocate_section(s1, s); |
3213 | + } |
3214 | + |
3215 | + /* relocate relocation entries if the relocation tables are |
3216 | + allocated in the executable */ |
3217 | + for(i = 1; i < s1->nb_sections; i++) { |
3218 | + s = s1->sections[i]; |
3219 | + if ((s->sh_flags & SHF_ALLOC) && |
3220 | + s->sh_type == SHT_RELX) { |
3221 | + relocate_rel(s1, s); |
3222 | + } |
3223 | + } |
3224 | + |
3225 | + /* get entry point address */ |
3226 | + if (file_type == TCC_OUTPUT_EXE) |
3227 | + ehdr.e_entry = (uplong)tcc_get_symbol_err(s1, "_start"); |
3228 | + else |
3229 | + ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */ |
3230 | + } |
3231 | + if (file_type == TCC_OUTPUT_EXE && s1->static_link) |
3232 | + fill_got(s1); |
3233 | + |
3234 | + /* write elf file */ |
3235 | + if (file_type == TCC_OUTPUT_OBJ) |
3236 | + mode = 0666; |
3237 | + else |
3238 | + mode = 0777; |
3239 | + unlink(filename); |
3240 | + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode); |
3241 | + if (fd < 0) { |
3242 | + tcc_error_noabort("could not write '%s'", filename); |
3243 | + goto fail; |
3244 | + } |
3245 | + f = fdopen(fd, "wb"); |
3246 | + if (s1->verbose) |
3247 | + printf("<- %s\n", filename); |
3248 | + |
3249 | +#ifdef TCC_TARGET_COFF |
3250 | + if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) { |
3251 | + tcc_output_coff(s1, f); |
3252 | + } else |
3253 | +#endif |
3254 | + if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { |
3255 | + sort_syms(s1, symtab_section); |
3256 | + |
3257 | + /* align to 4 */ |
3258 | + file_offset = (file_offset + 3) & -4; |
3259 | + |
3260 | + /* fill header */ |
3261 | + ehdr.e_ident[0] = ELFMAG0; |
3262 | + ehdr.e_ident[1] = ELFMAG1; |
3263 | + ehdr.e_ident[2] = ELFMAG2; |
3264 | + ehdr.e_ident[3] = ELFMAG3; |
3265 | + ehdr.e_ident[4] = ELFCLASSW; |
3266 | + ehdr.e_ident[5] = ELFDATA2LSB; |
3267 | + ehdr.e_ident[6] = EV_CURRENT; |
3268 | +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
3269 | + ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD; |
3270 | +#endif |
3271 | +#ifdef TCC_TARGET_ARM |
3272 | +#ifdef TCC_ARM_EABI |
3273 | + ehdr.e_ident[EI_OSABI] = 0; |
3274 | + ehdr.e_flags = 4 << 24; |
3275 | +#else |
3276 | + ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM; |
3277 | +#endif |
3278 | +#endif |
3279 | + switch(file_type) { |
3280 | + default: |
3281 | + case TCC_OUTPUT_EXE: |
3282 | + ehdr.e_type = ET_EXEC; |
3283 | + break; |
3284 | + case TCC_OUTPUT_DLL: |
3285 | + ehdr.e_type = ET_DYN; |
3286 | + break; |
3287 | + case TCC_OUTPUT_OBJ: |
3288 | + ehdr.e_type = ET_REL; |
3289 | + break; |
3290 | + } |
3291 | + ehdr.e_machine = EM_TCC_TARGET; |
3292 | + ehdr.e_version = EV_CURRENT; |
3293 | + ehdr.e_shoff = file_offset; |
3294 | + ehdr.e_ehsize = sizeof(ElfW(Ehdr)); |
3295 | + ehdr.e_shentsize = sizeof(ElfW(Shdr)); |
3296 | + ehdr.e_shnum = shnum; |
3297 | + ehdr.e_shstrndx = shnum - 1; |
3298 | + |
3299 | + fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f); |
3300 | + fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f); |
3301 | + offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr)); |
3302 | + |
3303 | + for(i=1;i<s1->nb_sections;i++) { |
3304 | + s = s1->sections[section_order[i]]; |
3305 | + if (s->sh_type != SHT_NOBITS) { |
3306 | + if (s->sh_type == SHT_DYNSYM) |
3307 | + patch_dynsym_undef(s1, s); |
3308 | + while (offset < s->sh_offset) { |
3309 | + fputc(0, f); |
3310 | + offset++; |
3311 | + } |
3312 | + size = s->sh_size; |
3313 | + fwrite(s->data, 1, size, f); |
3314 | + offset += size; |
3315 | + } |
3316 | + } |
3317 | + |
3318 | + /* output section headers */ |
3319 | + while (offset < ehdr.e_shoff) { |
3320 | + fputc(0, f); |
3321 | + offset++; |
3322 | + } |
3323 | + |
3324 | + for(i=0;i<s1->nb_sections;i++) { |
3325 | + sh = &shdr; |
3326 | + memset(sh, 0, sizeof(ElfW(Shdr))); |
3327 | + s = s1->sections[i]; |
3328 | + if (s) { |
3329 | + sh->sh_name = s->sh_name; |
3330 | + sh->sh_type = s->sh_type; |
3331 | + sh->sh_flags = s->sh_flags; |
3332 | + sh->sh_entsize = s->sh_entsize; |
3333 | + sh->sh_info = s->sh_info; |
3334 | + if (s->link) |
3335 | + sh->sh_link = s->link->sh_num; |
3336 | + sh->sh_addralign = s->sh_addralign; |
3337 | + sh->sh_addr = s->sh_addr; |
3338 | + sh->sh_offset = s->sh_offset; |
3339 | + sh->sh_size = s->sh_size; |
3340 | + } |
3341 | + fwrite(sh, 1, sizeof(ElfW(Shdr)), f); |
3342 | + } |
3343 | + } else { |
3344 | + tcc_output_binary(s1, f, section_order); |
3345 | + } |
3346 | + fclose(f); |
3347 | + |
3348 | + ret = 0; |
3349 | + the_end: |
3350 | + tcc_free(s1->symtab_to_dynsym); |
3351 | + tcc_free(section_order); |
3352 | + tcc_free(phdr); |
3353 | + tcc_free(s1->got_offsets); |
3354 | + return ret; |
3355 | +} |
3356 | + |
3357 | +LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) |
3358 | +{ |
3359 | + int ret; |
3360 | +#ifdef TCC_TARGET_PE |
3361 | + if (s->output_type != TCC_OUTPUT_OBJ) { |
3362 | + ret = pe_output_file(s, filename); |
3363 | + } else |
3364 | +#endif |
3365 | + { |
3366 | + ret = elf_output_file(s, filename); |
3367 | + } |
3368 | + return ret; |
3369 | +} |
3370 | + |
3371 | +static void *load_data(int fd, unsigned long file_offset, unsigned long size) |
3372 | +{ |
3373 | + void *data; |
3374 | + |
3375 | + data = tcc_malloc(size); |
3376 | + lseek(fd, file_offset, SEEK_SET); |
3377 | + read(fd, data, size); |
3378 | + return data; |
3379 | +} |
3380 | + |
3381 | +typedef struct SectionMergeInfo { |
3382 | + Section *s; /* corresponding existing section */ |
3383 | + unsigned long offset; /* offset of the new section in the existing section */ |
3384 | + uint8_t new_section; /* true if section 's' was added */ |
3385 | + uint8_t link_once; /* true if link once section */ |
3386 | +} SectionMergeInfo; |
3387 | + |
3388 | +/* load an object file and merge it with current files */ |
3389 | +/* XXX: handle correctly stab (debug) info */ |
3390 | +ST_FUNC int tcc_load_object_file(TCCState *s1, |
3391 | + int fd, unsigned long file_offset) |
3392 | +{ |
3393 | + ElfW(Ehdr) ehdr; |
3394 | + ElfW(Shdr) *shdr, *sh; |
3395 | + int size, i, j, offset, offseti, nb_syms, sym_index, ret; |
3396 | + unsigned char *strsec, *strtab; |
3397 | + int *old_to_new_syms; |
3398 | + char *sh_name, *name; |
3399 | + SectionMergeInfo *sm_table, *sm; |
3400 | + ElfW(Sym) *sym, *symtab; |
3401 | + ElfW_Rel *rel, *rel_end; |
3402 | + Section *s; |
3403 | + |
3404 | + int stab_index; |
3405 | + int stabstr_index; |
3406 | + |
3407 | + stab_index = stabstr_index = 0; |
3408 | + |
3409 | + if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr)) |
3410 | + goto fail1; |
3411 | + if (ehdr.e_ident[0] != ELFMAG0 || |
3412 | + ehdr.e_ident[1] != ELFMAG1 || |
3413 | + ehdr.e_ident[2] != ELFMAG2 || |
3414 | + ehdr.e_ident[3] != ELFMAG3) |
3415 | + goto fail1; |
3416 | + /* test if object file */ |
3417 | + if (ehdr.e_type != ET_REL) |
3418 | + goto fail1; |
3419 | + /* test CPU specific stuff */ |
3420 | + if (ehdr.e_ident[5] != ELFDATA2LSB || |
3421 | + ehdr.e_machine != EM_TCC_TARGET) { |
3422 | + fail1: |
3423 | + tcc_error_noabort("invalid object file"); |
3424 | + return -1; |
3425 | + } |
3426 | + /* read sections */ |
3427 | + shdr = load_data(fd, file_offset + ehdr.e_shoff, |
3428 | + sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
3429 | + sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum); |
3430 | + |
3431 | + /* load section names */ |
3432 | + sh = &shdr[ehdr.e_shstrndx]; |
3433 | + strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
3434 | + |
3435 | + /* load symtab and strtab */ |
3436 | + old_to_new_syms = NULL; |
3437 | + symtab = NULL; |
3438 | + strtab = NULL; |
3439 | + nb_syms = 0; |
3440 | + for(i = 1; i < ehdr.e_shnum; i++) { |
3441 | + sh = &shdr[i]; |
3442 | + if (sh->sh_type == SHT_SYMTAB) { |
3443 | + if (symtab) { |
3444 | + tcc_error_noabort("object must contain only one symtab"); |
3445 | + fail: |
3446 | + ret = -1; |
3447 | + goto the_end; |
3448 | + } |
3449 | + nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
3450 | + symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
3451 | + sm_table[i].s = symtab_section; |
3452 | + |
3453 | + /* now load strtab */ |
3454 | + sh = &shdr[sh->sh_link]; |
3455 | + strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size); |
3456 | + } |
3457 | + } |
3458 | + |
3459 | + /* now examine each section and try to merge its content with the |
3460 | + ones in memory */ |
3461 | + for(i = 1; i < ehdr.e_shnum; i++) { |
3462 | + /* no need to examine section name strtab */ |
3463 | + if (i == ehdr.e_shstrndx) |
3464 | + continue; |
3465 | + sh = &shdr[i]; |
3466 | + sh_name = strsec + sh->sh_name; |
3467 | + /* ignore sections types we do not handle */ |
3468 | + if (sh->sh_type != SHT_PROGBITS && |
3469 | + sh->sh_type != SHT_RELX && |
3470 | +#ifdef TCC_ARM_EABI |
3471 | + sh->sh_type != SHT_ARM_EXIDX && |
3472 | +#endif |
3473 | + sh->sh_type != SHT_NOBITS && |
3474 | + sh->sh_type != SHT_PREINIT_ARRAY && |
3475 | + sh->sh_type != SHT_INIT_ARRAY && |
3476 | + sh->sh_type != SHT_FINI_ARRAY && |
3477 | + strcmp(sh_name, ".stabstr") |
3478 | + ) |
3479 | + continue; |
3480 | + if (sh->sh_addralign < 1) |
3481 | + sh->sh_addralign = 1; |
3482 | + /* find corresponding section, if any */ |
3483 | + for(j = 1; j < s1->nb_sections;j++) { |
3484 | + s = s1->sections[j]; |
3485 | + if (!strcmp(s->name, sh_name)) { |
3486 | + if (!strncmp(sh_name, ".gnu.linkonce", |
3487 | + sizeof(".gnu.linkonce") - 1)) { |
3488 | + /* if a 'linkonce' section is already present, we |
3489 | + do not add it again. It is a little tricky as |
3490 | + symbols can still be defined in |
3491 | + it. */ |
3492 | + sm_table[i].link_once = 1; |
3493 | + goto next; |
3494 | + } else { |
3495 | + goto found; |
3496 | + } |
3497 | + } |
3498 | + } |
3499 | + /* not found: create new section */ |
3500 | + s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags); |
3501 | + /* take as much info as possible from the section. sh_link and |
3502 | + sh_info will be updated later */ |
3503 | + s->sh_addralign = sh->sh_addralign; |
3504 | + s->sh_entsize = sh->sh_entsize; |
3505 | + sm_table[i].new_section = 1; |
3506 | + found: |
3507 | + if (sh->sh_type != s->sh_type) { |
3508 | + tcc_error_noabort("invalid section type"); |
3509 | + goto fail; |
3510 | + } |
3511 | + |
3512 | + /* align start of section */ |
3513 | + offset = s->data_offset; |
3514 | + |
3515 | + if (0 == strcmp(sh_name, ".stab")) { |
3516 | + stab_index = i; |
3517 | + goto no_align; |
3518 | + } |
3519 | + if (0 == strcmp(sh_name, ".stabstr")) { |
3520 | + stabstr_index = i; |
3521 | + goto no_align; |
3522 | + } |
3523 | + |
3524 | + size = sh->sh_addralign - 1; |
3525 | + offset = (offset + size) & ~size; |
3526 | + if (sh->sh_addralign > s->sh_addralign) |
3527 | + s->sh_addralign = sh->sh_addralign; |
3528 | + s->data_offset = offset; |
3529 | + no_align: |
3530 | + sm_table[i].offset = offset; |
3531 | + sm_table[i].s = s; |
3532 | + /* concatenate sections */ |
3533 | + size = sh->sh_size; |
3534 | + if (sh->sh_type != SHT_NOBITS) { |
3535 | + unsigned char *ptr; |
3536 | + lseek(fd, file_offset + sh->sh_offset, SEEK_SET); |
3537 | + ptr = section_ptr_add(s, size); |
3538 | + read(fd, ptr, size); |
3539 | + } else { |
3540 | + s->data_offset += size; |
3541 | + } |
3542 | + next: ; |
3543 | + } |
3544 | + |
3545 | + /* //gr relocate stab strings */ |
3546 | + if (stab_index && stabstr_index) { |
3547 | + Stab_Sym *a, *b; |
3548 | + unsigned o; |
3549 | + s = sm_table[stab_index].s; |
3550 | + a = (Stab_Sym *)(s->data + sm_table[stab_index].offset); |
3551 | + b = (Stab_Sym *)(s->data + s->data_offset); |
3552 | + o = sm_table[stabstr_index].offset; |
3553 | + while (a < b) |
3554 | + a->n_strx += o, a++; |
3555 | + } |
3556 | + |
3557 | + /* second short pass to update sh_link and sh_info fields of new |
3558 | + sections */ |
3559 | + for(i = 1; i < ehdr.e_shnum; i++) { |
3560 | + s = sm_table[i].s; |
3561 | + if (!s || !sm_table[i].new_section) |
3562 | + continue; |
3563 | + sh = &shdr[i]; |
3564 | + if (sh->sh_link > 0) |
3565 | + s->link = sm_table[sh->sh_link].s; |
3566 | + if (sh->sh_type == SHT_RELX) { |
3567 | + s->sh_info = sm_table[sh->sh_info].s->sh_num; |
3568 | + /* update backward link */ |
3569 | + s1->sections[s->sh_info]->reloc = s; |
3570 | + } |
3571 | + } |
3572 | + sm = sm_table; |
3573 | + |
3574 | + /* resolve symbols */ |
3575 | + old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int)); |
3576 | + |
3577 | + sym = symtab + 1; |
3578 | + for(i = 1; i < nb_syms; i++, sym++) { |
3579 | + if (sym->st_shndx != SHN_UNDEF && |
3580 | + sym->st_shndx < SHN_LORESERVE) { |
3581 | + sm = &sm_table[sym->st_shndx]; |
3582 | + if (sm->link_once) { |
3583 | + /* if a symbol is in a link once section, we use the |
3584 | + already defined symbol. It is very important to get |
3585 | + correct relocations */ |
3586 | + if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
3587 | + name = strtab + sym->st_name; |
3588 | + sym_index = find_elf_sym(symtab_section, name); |
3589 | + if (sym_index) |
3590 | + old_to_new_syms[i] = sym_index; |
3591 | + } |
3592 | + continue; |
3593 | + } |
3594 | + /* if no corresponding section added, no need to add symbol */ |
3595 | + if (!sm->s) |
3596 | + continue; |
3597 | + /* convert section number */ |
3598 | + sym->st_shndx = sm->s->sh_num; |
3599 | + /* offset value */ |
3600 | + sym->st_value += sm->offset; |
3601 | + } |
3602 | + /* add symbol */ |
3603 | + name = strtab + sym->st_name; |
3604 | + sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size, |
3605 | + sym->st_info, sym->st_other, |
3606 | + sym->st_shndx, name); |
3607 | + old_to_new_syms[i] = sym_index; |
3608 | + } |
3609 | + |
3610 | + /* third pass to patch relocation entries */ |
3611 | + for(i = 1; i < ehdr.e_shnum; i++) { |
3612 | + s = sm_table[i].s; |
3613 | + if (!s) |
3614 | + continue; |
3615 | + sh = &shdr[i]; |
3616 | + offset = sm_table[i].offset; |
3617 | + switch(s->sh_type) { |
3618 | + case SHT_RELX: |
3619 | + /* take relocation offset information */ |
3620 | + offseti = sm_table[sh->sh_info].offset; |
3621 | + rel_end = (ElfW_Rel *)(s->data + s->data_offset); |
3622 | + for(rel = (ElfW_Rel *)(s->data + offset); |
3623 | + rel < rel_end; |
3624 | + rel++) { |
3625 | + int type; |
3626 | + unsigned sym_index; |
3627 | + /* convert symbol index */ |
3628 | + type = ELFW(R_TYPE)(rel->r_info); |
3629 | + sym_index = ELFW(R_SYM)(rel->r_info); |
3630 | + /* NOTE: only one symtab assumed */ |
3631 | + if (sym_index >= nb_syms) |
3632 | + goto invalid_reloc; |
3633 | + sym_index = old_to_new_syms[sym_index]; |
3634 | + /* ignore link_once in rel section. */ |
3635 | + if (!sym_index && !sm->link_once |
3636 | +#ifdef TCC_TARGET_ARM |
3637 | + && type != R_ARM_V4BX |
3638 | +#endif |
3639 | + ) { |
3640 | + invalid_reloc: |
3641 | + tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x", |
3642 | + i, strsec + sh->sh_name, rel->r_offset); |
3643 | + goto fail; |
3644 | + } |
3645 | + rel->r_info = ELFW(R_INFO)(sym_index, type); |
3646 | + /* offset the relocation offset */ |
3647 | + rel->r_offset += offseti; |
3648 | + } |
3649 | + break; |
3650 | + default: |
3651 | + break; |
3652 | + } |
3653 | + } |
3654 | + |
3655 | + ret = 0; |
3656 | + the_end: |
3657 | + tcc_free(symtab); |
3658 | + tcc_free(strtab); |
3659 | + tcc_free(old_to_new_syms); |
3660 | + tcc_free(sm_table); |
3661 | + tcc_free(strsec); |
3662 | + tcc_free(shdr); |
3663 | + return ret; |
3664 | +} |
3665 | + |
3666 | +typedef struct ArchiveHeader { |
3667 | + char ar_name[16]; /* name of this member */ |
3668 | + char ar_date[12]; /* file mtime */ |
3669 | + char ar_uid[6]; /* owner uid; printed as decimal */ |
3670 | + char ar_gid[6]; /* owner gid; printed as decimal */ |
3671 | + char ar_mode[8]; /* file mode, printed as octal */ |
3672 | + char ar_size[10]; /* file size, printed as decimal */ |
3673 | + char ar_fmag[2]; /* should contain ARFMAG */ |
3674 | +} ArchiveHeader; |
3675 | + |
3676 | +static int get_be32(const uint8_t *b) |
3677 | +{ |
3678 | + return b[3] | (b[2] << 8) | (b[1] << 16) | (b[0] << 24); |
3679 | +} |
3680 | + |
3681 | +/* load only the objects which resolve undefined symbols */ |
3682 | +static int tcc_load_alacarte(TCCState *s1, int fd, int size) |
3683 | +{ |
3684 | + int i, bound, nsyms, sym_index, off, ret; |
3685 | + uint8_t *data; |
3686 | + const char *ar_names, *p; |
3687 | + const uint8_t *ar_index; |
3688 | + ElfW(Sym) *sym; |
3689 | + |
3690 | + data = tcc_malloc(size); |
3691 | + if (read(fd, data, size) != size) |
3692 | + goto fail; |
3693 | + nsyms = get_be32(data); |
3694 | + ar_index = data + 4; |
3695 | + ar_names = ar_index + nsyms * 4; |
3696 | + |
3697 | + do { |
3698 | + bound = 0; |
3699 | + for(p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) { |
3700 | + sym_index = find_elf_sym(symtab_section, p); |
3701 | + if(sym_index) { |
3702 | + sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
3703 | + if(sym->st_shndx == SHN_UNDEF) { |
3704 | + off = get_be32(ar_index + i * 4) + sizeof(ArchiveHeader); |
3705 | +#if 0 |
3706 | + printf("%5d\t%s\t%08x\n", i, p, sym->st_shndx); |
3707 | +#endif |
3708 | + ++bound; |
3709 | + lseek(fd, off, SEEK_SET); |
3710 | + if(tcc_load_object_file(s1, fd, off) < 0) { |
3711 | + fail: |
3712 | + ret = -1; |
3713 | + goto the_end; |
3714 | + } |
3715 | + } |
3716 | + } |
3717 | + } |
3718 | + } while(bound); |
3719 | + ret = 0; |
3720 | + the_end: |
3721 | + tcc_free(data); |
3722 | + return ret; |
3723 | +} |
3724 | + |
3725 | +/* load a '.a' file */ |
3726 | +ST_FUNC int tcc_load_archive(TCCState *s1, int fd) |
3727 | +{ |
3728 | + ArchiveHeader hdr; |
3729 | + char ar_size[11]; |
3730 | + char ar_name[17]; |
3731 | + char magic[8]; |
3732 | + int size, len, i; |
3733 | + unsigned long file_offset; |
3734 | + |
3735 | + /* skip magic which was already checked */ |
3736 | + read(fd, magic, sizeof(magic)); |
3737 | + |
3738 | + for(;;) { |
3739 | + len = read(fd, &hdr, sizeof(hdr)); |
3740 | + if (len == 0) |
3741 | + break; |
3742 | + if (len != sizeof(hdr)) { |
3743 | + tcc_error_noabort("invalid archive"); |
3744 | + return -1; |
3745 | + } |
3746 | + memcpy(ar_size, hdr.ar_size, sizeof(hdr.ar_size)); |
3747 | + ar_size[sizeof(hdr.ar_size)] = '\0'; |
3748 | + size = strtol(ar_size, NULL, 0); |
3749 | + memcpy(ar_name, hdr.ar_name, sizeof(hdr.ar_name)); |
3750 | + for(i = sizeof(hdr.ar_name) - 1; i >= 0; i--) { |
3751 | + if (ar_name[i] != ' ') |
3752 | + break; |
3753 | + } |
3754 | + ar_name[i + 1] = '\0'; |
3755 | + // printf("name='%s' size=%d %s\n", ar_name, size, ar_size); |
3756 | + file_offset = lseek(fd, 0, SEEK_CUR); |
3757 | + /* align to even */ |
3758 | + size = (size + 1) & ~1; |
3759 | + if (!strcmp(ar_name, "/")) { |
3760 | + /* coff symbol table : we handle it */ |
3761 | + if(s1->alacarte_link) |
3762 | + return tcc_load_alacarte(s1, fd, size); |
3763 | + } else if (!strcmp(ar_name, "//") || |
3764 | + !strcmp(ar_name, "__.SYMDEF") || |
3765 | + !strcmp(ar_name, "__.SYMDEF/") || |
3766 | + !strcmp(ar_name, "ARFILENAMES/")) { |
3767 | + /* skip symbol table or archive names */ |
3768 | + } else { |
3769 | + if (tcc_load_object_file(s1, fd, file_offset) < 0) |
3770 | + return -1; |
3771 | + } |
3772 | + lseek(fd, file_offset + size, SEEK_SET); |
3773 | + } |
3774 | + return 0; |
3775 | +} |
3776 | + |
3777 | +#ifndef TCC_TARGET_PE |
3778 | +/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL |
3779 | + is referenced by the user (so it should be added as DT_NEEDED in |
3780 | + the generated ELF file) */ |
3781 | +ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) |
3782 | +{ |
3783 | + ElfW(Ehdr) ehdr; |
3784 | + ElfW(Shdr) *shdr, *sh, *sh1; |
3785 | + int i, j, nb_syms, nb_dts, sym_bind, ret; |
3786 | + ElfW(Sym) *sym, *dynsym; |
3787 | + ElfW(Dyn) *dt, *dynamic; |
3788 | + unsigned char *dynstr; |
3789 | + const char *name, *soname; |
3790 | + DLLReference *dllref; |
3791 | + |
3792 | + read(fd, &ehdr, sizeof(ehdr)); |
3793 | + |
3794 | + /* test CPU specific stuff */ |
3795 | + if (ehdr.e_ident[5] != ELFDATA2LSB || |
3796 | + ehdr.e_machine != EM_TCC_TARGET) { |
3797 | + tcc_error_noabort("bad architecture"); |
3798 | + return -1; |
3799 | + } |
3800 | + |
3801 | + /* read sections */ |
3802 | + shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum); |
3803 | + |
3804 | + /* load dynamic section and dynamic symbols */ |
3805 | + nb_syms = 0; |
3806 | + nb_dts = 0; |
3807 | + dynamic = NULL; |
3808 | + dynsym = NULL; /* avoid warning */ |
3809 | + dynstr = NULL; /* avoid warning */ |
3810 | + for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) { |
3811 | + switch(sh->sh_type) { |
3812 | + case SHT_DYNAMIC: |
3813 | + nb_dts = sh->sh_size / sizeof(ElfW(Dyn)); |
3814 | + dynamic = load_data(fd, sh->sh_offset, sh->sh_size); |
3815 | + break; |
3816 | + case SHT_DYNSYM: |
3817 | + nb_syms = sh->sh_size / sizeof(ElfW(Sym)); |
3818 | + dynsym = load_data(fd, sh->sh_offset, sh->sh_size); |
3819 | + sh1 = &shdr[sh->sh_link]; |
3820 | + dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size); |
3821 | + break; |
3822 | + default: |
3823 | + break; |
3824 | + } |
3825 | + } |
3826 | + |
3827 | + /* compute the real library name */ |
3828 | + soname = tcc_basename(filename); |
3829 | + |
3830 | + for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
3831 | + if (dt->d_tag == DT_SONAME) { |
3832 | + soname = dynstr + dt->d_un.d_val; |
3833 | + } |
3834 | + } |
3835 | + |
3836 | + /* if the dll is already loaded, do not load it */ |
3837 | + for(i = 0; i < s1->nb_loaded_dlls; i++) { |
3838 | + dllref = s1->loaded_dlls[i]; |
3839 | + if (!strcmp(soname, dllref->name)) { |
3840 | + /* but update level if needed */ |
3841 | + if (level < dllref->level) |
3842 | + dllref->level = level; |
3843 | + ret = 0; |
3844 | + goto the_end; |
3845 | + } |
3846 | + } |
3847 | + |
3848 | + // printf("loading dll '%s'\n", soname); |
3849 | + |
3850 | + /* add the dll and its level */ |
3851 | + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); |
3852 | + dllref->level = level; |
3853 | + strcpy(dllref->name, soname); |
3854 | + dynarray_add((void ***)&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
3855 | + |
3856 | + /* add dynamic symbols in dynsym_section */ |
3857 | + for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) { |
3858 | + sym_bind = ELFW(ST_BIND)(sym->st_info); |
3859 | + if (sym_bind == STB_LOCAL) |
3860 | + continue; |
3861 | + name = dynstr + sym->st_name; |
3862 | + add_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size, |
3863 | + sym->st_info, sym->st_other, sym->st_shndx, name); |
3864 | + } |
3865 | + |
3866 | + /* load all referenced DLLs */ |
3867 | + for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) { |
3868 | + switch(dt->d_tag) { |
3869 | + case DT_NEEDED: |
3870 | + name = dynstr + dt->d_un.d_val; |
3871 | + for(j = 0; j < s1->nb_loaded_dlls; j++) { |
3872 | + dllref = s1->loaded_dlls[j]; |
3873 | + if (!strcmp(name, dllref->name)) |
3874 | + goto already_loaded; |
3875 | + } |
3876 | + if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) { |
3877 | + tcc_error_noabort("referenced dll '%s' not found", name); |
3878 | + ret = -1; |
3879 | + goto the_end; |
3880 | + } |
3881 | + already_loaded: |
3882 | + break; |
3883 | + } |
3884 | + } |
3885 | + ret = 0; |
3886 | + the_end: |
3887 | + tcc_free(dynstr); |
3888 | + tcc_free(dynsym); |
3889 | + tcc_free(dynamic); |
3890 | + tcc_free(shdr); |
3891 | + return ret; |
3892 | +} |
3893 | + |
3894 | +#define LD_TOK_NAME 256 |
3895 | +#define LD_TOK_EOF (-1) |
3896 | + |
3897 | +/* return next ld script token */ |
3898 | +static int ld_next(TCCState *s1, char *name, int name_size) |
3899 | +{ |
3900 | + int c; |
3901 | + char *q; |
3902 | + |
3903 | + redo: |
3904 | + switch(ch) { |
3905 | + case ' ': |
3906 | + case '\t': |
3907 | + case '\f': |
3908 | + case '\v': |
3909 | + case '\r': |
3910 | + case '\n': |
3911 | + inp(); |
3912 | + goto redo; |
3913 | + case '/': |
3914 | + minp(); |
3915 | + if (ch == '*') { |
3916 | + file->buf_ptr = parse_comment(file->buf_ptr); |
3917 | + ch = file->buf_ptr[0]; |
3918 | + goto redo; |
3919 | + } else { |
3920 | + q = name; |
3921 | + *q++ = '/'; |
3922 | + goto parse_name; |
3923 | + } |
3924 | + break; |
3925 | + /* case 'a' ... 'z': */ |
3926 | + case 'a': |
3927 | + case 'b': |
3928 | + case 'c': |
3929 | + case 'd': |
3930 | + case 'e': |
3931 | + case 'f': |
3932 | + case 'g': |
3933 | + case 'h': |
3934 | + case 'i': |
3935 | + case 'j': |
3936 | + case 'k': |
3937 | + case 'l': |
3938 | + case 'm': |
3939 | + case 'n': |
3940 | + case 'o': |
3941 | + case 'p': |
3942 | + case 'q': |
3943 | + case 'r': |
3944 | + case 's': |
3945 | + case 't': |
3946 | + case 'u': |
3947 | + case 'v': |
3948 | + case 'w': |
3949 | + case 'x': |
3950 | + case 'y': |
3951 | + case 'z': |
3952 | + /* case 'A' ... 'z': */ |
3953 | + case 'A': |
3954 | + case 'B': |
3955 | + case 'C': |
3956 | + case 'D': |
3957 | + case 'E': |
3958 | + case 'F': |
3959 | + case 'G': |
3960 | + case 'H': |
3961 | + case 'I': |
3962 | + case 'J': |
3963 | + case 'K': |
3964 | + case 'L': |
3965 | + case 'M': |
3966 | + case 'N': |
3967 | + case 'O': |
3968 | + case 'P': |
3969 | + case 'Q': |
3970 | + case 'R': |
3971 | + case 'S': |
3972 | + case 'T': |
3973 | + case 'U': |
3974 | + case 'V': |
3975 | + case 'W': |
3976 | + case 'X': |
3977 | + case 'Y': |
3978 | + case 'Z': |
3979 | + case '_': |
3980 | + case '\\': |
3981 | + case '.': |
3982 | + case '$': |
3983 | + case '~': |
3984 | + q = name; |
3985 | + parse_name: |
3986 | + for(;;) { |
3987 | + if (!((ch >= 'a' && ch <= 'z') || |
3988 | + (ch >= 'A' && ch <= 'Z') || |
3989 | + (ch >= '0' && ch <= '9') || |
3990 | + strchr("/.-_+=$:\\,~", ch))) |
3991 | + break; |
3992 | + if ((q - name) < name_size - 1) { |
3993 | + *q++ = ch; |
3994 | + } |
3995 | + minp(); |
3996 | + } |
3997 | + *q = '\0'; |
3998 | + c = LD_TOK_NAME; |
3999 | + break; |
4000 | + case CH_EOF: |
4001 | + c = LD_TOK_EOF; |
4002 | + break; |
4003 | + default: |
4004 | + c = ch; |
4005 | + inp(); |
4006 | + break; |
4007 | + } |
4008 | +#if 0 |
4009 | + printf("tok=%c %d\n", c, c); |
4010 | + if (c == LD_TOK_NAME) |
4011 | + printf(" name=%s\n", name); |
4012 | +#endif |
4013 | + return c; |
4014 | +} |
4015 | + |
4016 | +/* |
4017 | + * Extract the file name from the library name |
4018 | + * |
4019 | + * /!\ No test on filename capacity, be careful |
4020 | + */ |
4021 | +static void libname_to_filename(TCCState *s1, const char libname[], char filename[]) |
4022 | +{ |
4023 | + if (!s1->static_link) { |
4024 | + sprintf(filename, "lib%s.so", libname); |
4025 | + } else { |
4026 | + sprintf(filename, "lib%s.a", libname); |
4027 | + } |
4028 | +} |
4029 | + |
4030 | +static int ld_add_file(TCCState *s1, const char filename[]) |
4031 | +{ |
4032 | + int ret; |
4033 | + |
4034 | + ret = tcc_add_file_internal(s1, filename, 0); |
4035 | + if (ret) |
4036 | + ret = tcc_add_dll(s1, filename, 0); |
4037 | + return ret; |
4038 | +} |
4039 | + |
4040 | +static inline int new_undef_syms(void) |
4041 | +{ |
4042 | + int ret = 0; |
4043 | + ret = new_undef_sym; |
4044 | + new_undef_sym = 0; |
4045 | + return ret; |
4046 | +} |
4047 | + |
4048 | +static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed) |
4049 | +{ |
4050 | + char filename[1024], libname[1024]; |
4051 | + int t, group, nblibs = 0, ret = 0; |
4052 | + char **libs = NULL; |
4053 | + |
4054 | + group = !strcmp(cmd, "GROUP"); |
4055 | + if (!as_needed) |
4056 | + new_undef_syms(); |
4057 | + t = ld_next(s1, filename, sizeof(filename)); |
4058 | + if (t != '(') |
4059 | + expect("("); |
4060 | + t = ld_next(s1, filename, sizeof(filename)); |
4061 | + for(;;) { |
4062 | + libname[0] = '\0'; |
4063 | + if (t == LD_TOK_EOF) { |
4064 | + tcc_error_noabort("unexpected end of file"); |
4065 | + ret = -1; |
4066 | + goto lib_parse_error; |
4067 | + } else if (t == ')') { |
4068 | + break; |
4069 | + } else if (t == '-') { |
4070 | + t = ld_next(s1, filename, sizeof(filename)); |
4071 | + if ((t != LD_TOK_NAME) || (filename[0] != 'l')) { |
4072 | + tcc_error_noabort("library name expected"); |
4073 | + ret = -1; |
4074 | + goto lib_parse_error; |
4075 | + } |
4076 | + strcpy(libname, &filename[1]); |
4077 | + libname_to_filename(s1, libname, filename); |
4078 | + } else if (t != LD_TOK_NAME) { |
4079 | + tcc_error_noabort("filename expected"); |
4080 | + ret = -1; |
4081 | + goto lib_parse_error; |
4082 | + } |
4083 | + if (!strcmp(filename, "AS_NEEDED")) { |
4084 | + ret = ld_add_file_list(s1, cmd, 1); |
4085 | + if (ret) |
4086 | + goto lib_parse_error; |
4087 | + } else { |
4088 | + /* TODO: Implement AS_NEEDED support. Ignore it for now */ |
4089 | + if (!as_needed) { |
4090 | + ret = ld_add_file(s1, filename); |
4091 | + if (ret) |
4092 | + goto lib_parse_error; |
4093 | + if (group) { |
4094 | + /* Add the filename *and* the libname to avoid future conversions */ |
4095 | + dynarray_add((void ***) &libs, &nblibs, tcc_strdup(filename)); |
4096 | + if (libname[0] != '\0') |
4097 | + dynarray_add((void ***) &libs, &nblibs, tcc_strdup(libname)); |
4098 | + } |
4099 | + } |
4100 | + } |
4101 | + t = ld_next(s1, filename, sizeof(filename)); |
4102 | + if (t == ',') { |
4103 | + t = ld_next(s1, filename, sizeof(filename)); |
4104 | + } |
4105 | + } |
4106 | + if (group && !as_needed) { |
4107 | + while (new_undef_syms()) { |
4108 | + int i; |
4109 | + |
4110 | + for (i = 0; i < nblibs; i ++) |
4111 | + ld_add_file(s1, libs[i]); |
4112 | + } |
4113 | + } |
4114 | +lib_parse_error: |
4115 | + dynarray_reset(&libs, &nblibs); |
4116 | + return ret; |
4117 | +} |
4118 | + |
4119 | +/* interpret a subset of GNU ldscripts to handle the dummy libc.so |
4120 | + files */ |
4121 | +ST_FUNC int tcc_load_ldscript(TCCState *s1) |
4122 | +{ |
4123 | + char cmd[64]; |
4124 | + char filename[1024]; |
4125 | + int t, ret; |
4126 | + |
4127 | + ch = file->buf_ptr[0]; |
4128 | + ch = handle_eob(); |
4129 | + for(;;) { |
4130 | + t = ld_next(s1, cmd, sizeof(cmd)); |
4131 | + if (t == LD_TOK_EOF) |
4132 | + return 0; |
4133 | + else if (t != LD_TOK_NAME) |
4134 | + return -1; |
4135 | + if (!strcmp(cmd, "INPUT") || |
4136 | + !strcmp(cmd, "GROUP")) { |
4137 | + ret = ld_add_file_list(s1, cmd, 0); |
4138 | + if (ret) |
4139 | + return ret; |
4140 | + } else if (!strcmp(cmd, "OUTPUT_FORMAT") || |
4141 | + !strcmp(cmd, "TARGET")) { |
4142 | + /* ignore some commands */ |
4143 | + t = ld_next(s1, cmd, sizeof(cmd)); |
4144 | + if (t != '(') |
4145 | + expect("("); |
4146 | + for(;;) { |
4147 | + t = ld_next(s1, filename, sizeof(filename)); |
4148 | + if (t == LD_TOK_EOF) { |
4149 | + tcc_error_noabort("unexpected end of file"); |
4150 | + return -1; |
4151 | + } else if (t == ')') { |
4152 | + break; |
4153 | + } |
4154 | + } |
4155 | + } else { |
4156 | + return -1; |
4157 | + } |
4158 | + } |
4159 | + return 0; |
4160 | +} |
4161 | +#endif /* ndef TCC_TARGET_PE */ |
4162 | |
4163 | === added directory '.pc/0002-Evaluate-configure-arguments.patch' |
4164 | === added file '.pc/0002-Evaluate-configure-arguments.patch/configure' |
4165 | --- .pc/0002-Evaluate-configure-arguments.patch/configure 1970-01-01 00:00:00 +0000 |
4166 | +++ .pc/0002-Evaluate-configure-arguments.patch/configure 2012-11-13 09:46:40 +0000 |
4167 | @@ -0,0 +1,496 @@ |
4168 | +#!/bin/sh |
4169 | +# |
4170 | +# tcc configure script (c) 2003 Fabrice Bellard |
4171 | + |
4172 | +# set temporary file name |
4173 | +if test ! -z "$TMPDIR" ; then |
4174 | + TMPDIR1="${TMPDIR}" |
4175 | +elif test ! -z "$TEMPDIR" ; then |
4176 | + TMPDIR1="${TEMPDIR}" |
4177 | +else |
4178 | + TMPDIR1="/tmp" |
4179 | +fi |
4180 | + |
4181 | +# bashism: TMPN="${TMPDIR1}/tcc-conf-${RANDOM}-$$-${RANDOM}.c" |
4182 | +TMPN="./conftest-$$" |
4183 | + |
4184 | +TMPC=$TMPN.c |
4185 | +TMPH=$TMPN.h |
4186 | +TMPO=$TMPN.o |
4187 | +TMPE=$TMPN |
4188 | + |
4189 | +# default parameters |
4190 | +build_cross="no" |
4191 | +use_libgcc="no" |
4192 | +prefix="" |
4193 | +execprefix="" |
4194 | +bindir="" |
4195 | +libdir="" |
4196 | +tccdir="" |
4197 | +includedir="" |
4198 | +mandir="" |
4199 | +infodir="" |
4200 | +sysroot="" |
4201 | +cross_prefix="" |
4202 | +cc="gcc" |
4203 | +host_cc="gcc" |
4204 | +ar="ar" |
4205 | +strip="strip" |
4206 | +cygwin="no" |
4207 | +cpu=`uname -m` |
4208 | + |
4209 | +tcc_sysincludepaths="" |
4210 | +tcc_libpaths="" |
4211 | +tcc_crtprefix="" |
4212 | +tcc_elfinterp="" |
4213 | + |
4214 | +case "$cpu" in |
4215 | + i386|i486|i586|i686|i86pc|BePC|i686-AT386) |
4216 | + cpu="x86" |
4217 | + ;; |
4218 | + x86_64) |
4219 | + cpu="x86-64" |
4220 | + ;; |
4221 | + arm|armv4l|armv5tel|armv5tejl|armv6j|armv7a|armv7l) |
4222 | + cpu="armv4l" |
4223 | + ;; |
4224 | + alpha) |
4225 | + cpu="alpha" |
4226 | + ;; |
4227 | + "Power Macintosh"|ppc|ppc64) |
4228 | + cpu="powerpc" |
4229 | + ;; |
4230 | + mips) |
4231 | + cpu="mips" |
4232 | + ;; |
4233 | + s390) |
4234 | + cpu="s390" |
4235 | + ;; |
4236 | + *) |
4237 | + cpu="unknown" |
4238 | + ;; |
4239 | +esac |
4240 | +gprof="no" |
4241 | +bigendian="no" |
4242 | +mingw32="no" |
4243 | +LIBSUF=".a" |
4244 | +EXESUF="" |
4245 | + |
4246 | +# OS specific |
4247 | +targetos=`uname -s` |
4248 | +case $targetos in |
4249 | +MINGW32*) |
4250 | +mingw32="yes" |
4251 | +;; |
4252 | +DragonFly) |
4253 | +noldl="yes" |
4254 | +;; |
4255 | +OpenBSD) |
4256 | +noldl="yes" |
4257 | +;; |
4258 | +*) ;; |
4259 | +esac |
4260 | + |
4261 | +# find source path |
4262 | +# XXX: we assume an absolute path is given when launching configure, |
4263 | +# except in './configure' case. |
4264 | +source_path=${0%configure} |
4265 | +source_path=${source_path%/} |
4266 | +source_path_used="yes" |
4267 | +if test -z "$source_path" -o "$source_path" = "." ; then |
4268 | + source_path=`pwd` |
4269 | + source_path_used="no" |
4270 | +fi |
4271 | + |
4272 | +for opt do |
4273 | + case "$opt" in |
4274 | + --prefix=*) prefix=`echo $opt | cut -d '=' -f 2` |
4275 | + ;; |
4276 | + --exec-prefix=*) execprefix=`echo $opt | cut -d '=' -f 2` |
4277 | + ;; |
4278 | + --tccdir=*) tccdir=`echo $opt | cut -d '=' -f 2` |
4279 | + ;; |
4280 | + --bindir=*) bindir=`echo $opt | cut -d '=' -f 2` |
4281 | + ;; |
4282 | + --libdir=*) libdir=`echo $opt | cut -d '=' -f 2` |
4283 | + ;; |
4284 | + --includedir=*) includedir=`echo $opt | cut -d '=' -f 2` |
4285 | + ;; |
4286 | + --sharedir=*) sharedir=`echo $opt | cut -d '=' -f 2` |
4287 | + ;; |
4288 | + --mandir=*) mandir=`echo $opt | cut -d '=' -f 2` |
4289 | + ;; |
4290 | + --infodir=*) infodir=`echo $opt | cut -d '=' -f 2` |
4291 | + ;; |
4292 | + --docdir=*) docdir=`echo $opt | cut -d '=' -f 2` |
4293 | + ;; |
4294 | + --sysroot=*) sysroot=`echo $opt | cut -d '=' -f 2` |
4295 | + ;; |
4296 | + --source-path=*) source_path=`echo $opt | cut -d '=' -f 2` |
4297 | + ;; |
4298 | + --cross-prefix=*) cross_prefix=`echo $opt | cut -d '=' -f 2` |
4299 | + ;; |
4300 | + --cc=*) cc=`echo $opt | cut -d '=' -f 2` |
4301 | + ;; |
4302 | + --extra-cflags=*) CFLAGS="${opt#--extra-cflags=}" |
4303 | + ;; |
4304 | + --extra-ldflags=*) LDFLAGS="${opt#--extra-ldflags=}" |
4305 | + ;; |
4306 | + --extra-libs=*) extralibs=${opt#--extra-libs=} |
4307 | + ;; |
4308 | + --sysincludepaths=*) tcc_sysincludepaths=`echo $opt | cut -d '=' -f 2` |
4309 | + ;; |
4310 | + --libpaths=*) tcc_libpaths=`echo $opt | cut -d '=' -f 2` |
4311 | + ;; |
4312 | + --crtprefix=*) tcc_crtprefix=`echo $opt | cut -d '=' -f 2` |
4313 | + ;; |
4314 | + --elfinterp=*) tcc_elfinterp=`echo $opt | cut -d '=' -f 2` |
4315 | + ;; |
4316 | + --cpu=*) cpu=`echo $opt | cut -d '=' -f 2` |
4317 | + ;; |
4318 | + --enable-gprof) gprof="yes" |
4319 | + ;; |
4320 | + --enable-mingw32) mingw32="yes" ; cross_prefix="i686-pc-mingw32-" ; cpu=x86 |
4321 | + ;; |
4322 | + --enable-cygwin) mingw32="yes" ; cygwin="yes" ; cross_prefix="mingw32-" ; cpu=x86 |
4323 | + ;; |
4324 | + --enable-cross) build_cross="yes" |
4325 | + ;; |
4326 | + --disable-static) disable_static="yes" |
4327 | + ;; |
4328 | + --disable-rpath) disable_rpath="yes" |
4329 | + ;; |
4330 | + --strip-binaries) strip_binaries="yes" |
4331 | + ;; |
4332 | + --with-libgcc) use_libgcc="yes" |
4333 | + ;; |
4334 | + --with-selinux) have_selinux="yes" |
4335 | + ;; |
4336 | + --help|-h) show_help="yes" |
4337 | + ;; |
4338 | + *) echo "configure: WARNING: unrecognized option $opt" |
4339 | + ;; |
4340 | + esac |
4341 | +done |
4342 | + |
4343 | +# Checking for CFLAGS |
4344 | +if test -z "$CFLAGS"; then |
4345 | + CFLAGS="-Wall -g -O2" |
4346 | +fi |
4347 | + |
4348 | +cc="${cross_prefix}${cc}" |
4349 | +ar="${cross_prefix}${ar}" |
4350 | +strip="${cross_prefix}${strip}" |
4351 | + |
4352 | +if test "$mingw32" = "yes" ; then |
4353 | + LIBSUF=".lib" |
4354 | + EXESUF=".exe" |
4355 | +fi |
4356 | + |
4357 | +if test -z "$cross_prefix" ; then |
4358 | + |
4359 | +# --- |
4360 | +# big/little endian test |
4361 | +cat > $TMPC << EOF |
4362 | +#include <inttypes.h> |
4363 | +int main(int argc, char ** argv){ |
4364 | + volatile uint32_t i=0x01234567; |
4365 | + return (*((uint8_t*)(&i))) == 0x67; |
4366 | +} |
4367 | +EOF |
4368 | + |
4369 | +if $cc -o $TMPE $TMPC 2>/dev/null ; then |
4370 | + $TMPE && bigendian="yes" |
4371 | +else |
4372 | + echo big/little test failed |
4373 | +fi |
4374 | + |
4375 | +else |
4376 | + |
4377 | +# if cross compiling, cannot launch a program, so make a static guess |
4378 | +if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then |
4379 | + bigendian="yes" |
4380 | +fi |
4381 | + |
4382 | +fi |
4383 | + |
4384 | +# check gcc version |
4385 | +cat > $TMPC <<EOF |
4386 | +int main(void) { |
4387 | +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2) |
4388 | +return 0; |
4389 | +#else |
4390 | +#error gcc < 3.2 |
4391 | +#endif |
4392 | +} |
4393 | +EOF |
4394 | + |
4395 | +gcc_major="2" |
4396 | +if $cc -o $TMPO $TMPC 2> /dev/null ; then |
4397 | + gcc_major="3" |
4398 | +fi |
4399 | +cat > $TMPC <<EOF |
4400 | +int main(void) { |
4401 | +#if __GNUC__ >= 4 |
4402 | +return 0; |
4403 | +#else |
4404 | +#error gcc < 4 |
4405 | +#endif |
4406 | +} |
4407 | +EOF |
4408 | + |
4409 | +if $cc -o $TMPO $TMPC 2> /dev/null ; then |
4410 | + gcc_major="4" |
4411 | +fi |
4412 | + |
4413 | +if test x"$show_help" = "xyes" ; then |
4414 | +cat << EOF |
4415 | + |
4416 | +Usage: configure [options] |
4417 | +Options: [defaults in brackets after descriptions] |
4418 | + |
4419 | +EOF |
4420 | +echo "Standard options:" |
4421 | +echo " --help print this message" |
4422 | +echo " --prefix=PREFIX install in PREFIX [$prefix]" |
4423 | +echo " --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX" |
4424 | +echo " [same as prefix]" |
4425 | +echo " --bindir=DIR user executables in DIR [EPREFIX/bin]" |
4426 | +echo " --libdir=DIR object code libraries in DIR [EPREFIX/lib]" |
4427 | +echo " --tccdir=DIR installation directory [EPREFIX/lib/tcc]" |
4428 | +echo " --includedir=DIR C header files in DIR [PREFIX/include]" |
4429 | +echo " --sharedir=DIR documentation root DIR [PREFIX]/share" |
4430 | +echo " --docdir=DIR documentation in DIR [SHAREDIR/doc/tcc]" |
4431 | +echo " --mandir=DIR man documentation in DIR [SHAREDIR/man]" |
4432 | +echo " --infodir=DIR info documentation in DIR [SHAREDIR/info]" |
4433 | +echo "" |
4434 | +echo "Advanced options (experts only):" |
4435 | +echo " --source-path=PATH path of source code [$source_path]" |
4436 | +echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" |
4437 | +echo " --sysroot=PREFIX prepend PREFIX to library/include paths []" |
4438 | +echo " --cc=CC use C compiler CC [$cc]" |
4439 | +echo " --disable-static make libtcc.so instead of libtcc.a" |
4440 | +echo " --disable-rpath disable use of -rpath with the above" |
4441 | +echo " --strip-binaries strip symbol tables from resulting binaries" |
4442 | +echo " --with-libgcc use /lib/libgcc_s.so.1 instead of libtcc.a" |
4443 | +echo " --enable-mingw32 build windows version on linux with mingw32" |
4444 | +echo " --enable-cygwin build windows version on windows with cygwin" |
4445 | +echo " [requires cygwin and mingw32-make]" |
4446 | +echo " --enable-cross build cross compilers" |
4447 | +echo " --extra-cflags= extra compiler flags" |
4448 | +echo " --extra-ldflags= extra linker options" |
4449 | +echo " --with-selinux use mmap instead of exec mem" |
4450 | +echo " [requires write access to /tmp]" |
4451 | +echo " --sysincludepaths=... specify system include paths, colon separated" |
4452 | +echo " --libpaths=... specify system library paths, colon separated" |
4453 | +echo " --crtprefix=... specify locations of crt?.o, colon separated" |
4454 | +echo " --elfinterp=... specify elf interpreter" |
4455 | +echo "" |
4456 | +#echo "NOTE: The object files are build at the place where configure is launched" |
4457 | +exit 1 |
4458 | +fi |
4459 | + |
4460 | +if test "$mingw32" = "yes" ; then |
4461 | + if test x"$tccdir" = x""; then |
4462 | + tccdir="tcc" |
4463 | + fi |
4464 | + if test -z "$prefix" ; then |
4465 | + prefix="C:/Program Files/${tccdir}" |
4466 | + fi |
4467 | + if test -z "$sharedir" ; then |
4468 | + sharedir="${prefix}" |
4469 | + fi |
4470 | + execprefix="$prefix" |
4471 | + bindir="${prefix}" |
4472 | + tccdir="${prefix}" |
4473 | + libdir="${prefix}/lib" |
4474 | + docdir="${sharedir}/doc" |
4475 | + mandir="${sharedir}/man" |
4476 | + infodir="${sharedir}/info" |
4477 | +else |
4478 | + if test -z "$prefix" ; then |
4479 | + prefix="/usr/local" |
4480 | + fi |
4481 | + if test -z "$sharedir" ; then |
4482 | + sharedir="${prefix}/share" |
4483 | + fi |
4484 | + if test x"$execprefix" = x""; then |
4485 | + execprefix="${prefix}" |
4486 | + fi |
4487 | + if test x"$libdir" = x""; then |
4488 | + libdir="${execprefix}/lib" |
4489 | + fi |
4490 | + if test x"$bindir" = x""; then |
4491 | + bindir="${execprefix}/bin" |
4492 | + fi |
4493 | + if test x"$tccdir" = x""; then |
4494 | + tccdir="tcc" |
4495 | + fi |
4496 | + if test x"$docdir" = x""; then |
4497 | + docdir="${sharedir}/doc/${tccdir}" |
4498 | + fi |
4499 | + if test x"$mandir" = x""; then |
4500 | + mandir="${sharedir}/man" |
4501 | + fi |
4502 | + if test x"$infodir" = x""; then |
4503 | + infodir="${sharedir}/info" |
4504 | + fi |
4505 | + tccdir="${libdir}/${tccdir}" |
4506 | +fi # mingw32 |
4507 | + |
4508 | +if test x"$includedir" = x""; then |
4509 | +includedir="${prefix}/include" |
4510 | +fi |
4511 | + |
4512 | +echo "Binary directory $bindir" |
4513 | +echo "TinyCC directory $tccdir" |
4514 | +echo "Library directory $libdir" |
4515 | +echo "Include directory $includedir" |
4516 | +echo "Manual directory $mandir" |
4517 | +echo "Info directory $infodir" |
4518 | +echo "Doc directory $docdir" |
4519 | +echo "Target root prefix $sysroot" |
4520 | +echo "Source path $source_path" |
4521 | +echo "C compiler $cc" |
4522 | +echo "Target OS $targetos" |
4523 | +echo "CPU $cpu" |
4524 | +echo "Big Endian $bigendian" |
4525 | +echo "gprof enabled $gprof" |
4526 | +echo "cross compilers $build_cross" |
4527 | +echo "use libgcc $use_libgcc" |
4528 | + |
4529 | +echo "Creating config.mak and config.h" |
4530 | + |
4531 | +echo "# Automatically generated by configure - do not modify" > config.mak |
4532 | +echo "/* Automatically generated by configure - do not modify */" > $TMPH |
4533 | + |
4534 | +echo "prefix=$prefix" >> config.mak |
4535 | +echo "bindir=\$(DESTDIR)$bindir" >> config.mak |
4536 | +echo "tccdir=\$(DESTDIR)$tccdir" >> config.mak |
4537 | +echo "libdir=\$(DESTDIR)$libdir" >> config.mak |
4538 | +echo "ln_libdir=$libdir" >> config.mak |
4539 | +echo "includedir=\$(DESTDIR)$includedir" >> config.mak |
4540 | +echo "mandir=\$(DESTDIR)$mandir" >> config.mak |
4541 | +echo "infodir=\$(DESTDIR)$infodir" >> config.mak |
4542 | +echo "docdir=\$(DESTDIR)$docdir" >> config.mak |
4543 | +print_var1() |
4544 | +{ |
4545 | + echo "#ifndef $1" >> $TMPH |
4546 | + echo "# define $1 \"$2\"" >> $TMPH |
4547 | + echo "#endif" >> $TMPH |
4548 | +} |
4549 | +print_var2() |
4550 | +{ |
4551 | + if test -n "$2"; then print_var1 $1 "$2"; fi |
4552 | +} |
4553 | +print_var2 CONFIG_SYSROOT "$sysroot" |
4554 | +print_var1 CONFIG_TCCDIR "$tccdir" |
4555 | +print_var2 CONFIG_TCC_SYSINCLUDEPATHS "$tcc_sysincludepaths" |
4556 | +print_var2 CONFIG_TCC_LIBPATHS "$tcc_libpaths" |
4557 | +print_var2 CONFIG_TCC_CRTPREFIX "$tcc_crtprefix" |
4558 | +print_var2 CONFIG_TCC_ELFINTERP "$tcc_elfinterp" |
4559 | + |
4560 | +echo "CC=$cc" >> config.mak |
4561 | +echo "GCC_MAJOR=$gcc_major" >> config.mak |
4562 | +echo "#define GCC_MAJOR $gcc_major" >> $TMPH |
4563 | +echo "HOST_CC=$host_cc" >> config.mak |
4564 | +echo "AR=$ar" >> config.mak |
4565 | +echo "STRIP=$strip -s -R .comment -R .note" >> config.mak |
4566 | +echo "CFLAGS=$CFLAGS" >> config.mak |
4567 | +echo "LDFLAGS=$LDFLAGS" >> config.mak |
4568 | +echo "LIBSUF=$LIBSUF" >> config.mak |
4569 | +echo "EXESUF=$EXESUF" >> config.mak |
4570 | + |
4571 | +if test "$cpu" = "x86" ; then |
4572 | + echo "ARCH=i386" >> config.mak |
4573 | + echo "#define HOST_I386 1" >> $TMPH |
4574 | +elif test "$cpu" = "x86-64" ; then |
4575 | + echo "ARCH=x86-64" >> config.mak |
4576 | + echo "#define HOST_X86_64 1" >> $TMPH |
4577 | +elif test "$cpu" = "armv4l" ; then |
4578 | + echo "ARCH=arm" >> config.mak |
4579 | + echo "#define HOST_ARM 1" >> $TMPH |
4580 | +elif test "$cpu" = "powerpc" ; then |
4581 | + echo "ARCH=ppc" >> config.mak |
4582 | + echo "#define HOST_PPC 1" >> $TMPH |
4583 | +elif test "$cpu" = "mips" ; then |
4584 | + echo "ARCH=mips" >> config.mak |
4585 | + echo "#define HOST_MIPS 1" >> $TMPH |
4586 | +elif test "$cpu" = "s390" ; then |
4587 | + echo "ARCH=s390" >> config.mak |
4588 | + echo "#define HOST_S390 1" >> $TMPH |
4589 | +elif test "$cpu" = "alpha" ; then |
4590 | + echo "ARCH=alpha" >> config.mak |
4591 | + echo "#define HOST_ALPHA 1" >> $TMPH |
4592 | +else |
4593 | + echo "Unsupported CPU" |
4594 | + exit 1 |
4595 | +fi |
4596 | +echo "TARGETOS=$targetos" >> config.mak |
4597 | +if test "$noldl" = "yes" ; then |
4598 | + echo "CONFIG_NOLDL=yes" >> config.mak |
4599 | +fi |
4600 | +if test "$mingw32" = "yes" ; then |
4601 | + echo "CONFIG_WIN32=yes" >> config.mak |
4602 | + echo "#define CONFIG_WIN32 1" >> $TMPH |
4603 | +fi |
4604 | +if test "$cygwin" = "yes" ; then |
4605 | + echo "#ifndef _WIN32" >> $TMPH |
4606 | + echo "#define _WIN32" >> $TMPH |
4607 | + echo "#endif" >> $TMPH |
4608 | + echo "AR=ar" >> config.mak |
4609 | +fi |
4610 | +if test "$bigendian" = "yes" ; then |
4611 | + echo "WORDS_BIGENDIAN=yes" >> config.mak |
4612 | + echo "#define WORDS_BIGENDIAN 1" >> $TMPH |
4613 | +fi |
4614 | +if test "$gprof" = "yes" ; then |
4615 | + echo "TARGET_GPROF=yes" >> config.mak |
4616 | + echo "#define HAVE_GPROF 1" >> $TMPH |
4617 | +fi |
4618 | +if test "$build_cross" = "yes" ; then |
4619 | + echo "CONFIG_CROSS=yes" >> config.mak |
4620 | +fi |
4621 | +if test "$disable_static" = "yes" ; then |
4622 | + echo "DISABLE_STATIC=yes" >> config.mak |
4623 | +fi |
4624 | +if test "$disable_rpath" = "yes" ; then |
4625 | + echo "DISABLE_RPATH=yes" >> config.mak |
4626 | +fi |
4627 | +if test "$strip_binaries" = "yes" ; then |
4628 | + echo "STRIP_BINARIES=yes" >> config.mak |
4629 | +fi |
4630 | +if test "$use_libgcc" = "yes" ; then |
4631 | + echo "#define CONFIG_USE_LIBGCC" >> $TMPH |
4632 | + echo "CONFIG_USE_LIBGCC=yes" >> config.mak |
4633 | +fi |
4634 | +if test "$have_selinux" = "yes" ; then |
4635 | + echo "#define HAVE_SELINUX" >> $TMPH |
4636 | + echo "HAVE_SELINUX=yes" >> config.mak |
4637 | +fi |
4638 | +version=`head $source_path/VERSION` |
4639 | +echo "VERSION=$version" >>config.mak |
4640 | +echo "#define TCC_VERSION \"$version\"" >> $TMPH |
4641 | +echo "@set VERSION $version" > config.texi |
4642 | + |
4643 | +# build tree in object directory if source path is different from current one |
4644 | +if test "$source_path_used" = "yes" ; then |
4645 | + DIRS="tests" |
4646 | + FILES="Makefile tests/Makefile" |
4647 | + for dir in $DIRS ; do |
4648 | + mkdir -p $dir |
4649 | + done |
4650 | + for f in $FILES ; do |
4651 | + ln -sf $source_path/$f $f |
4652 | + done |
4653 | +fi |
4654 | +echo "SRC_PATH=$source_path" >> config.mak |
4655 | + |
4656 | +diff $TMPH config.h >/dev/null 2>&1 |
4657 | +if test $? -ne 0 ; then |
4658 | + mv -f $TMPH config.h |
4659 | +else |
4660 | + echo "config.h is unchanged" |
4661 | +fi |
4662 | + |
4663 | +rm -f $TMPN* |
4664 | |
4665 | === removed directory '.pc/0002-Fix-a-typo-in-an-error-about-size-with-bounded-ptr.patch' |
4666 | === removed file '.pc/0002-Fix-a-typo-in-an-error-about-size-with-bounded-ptr.patch/i386-gen.c' |
4667 | --- .pc/0002-Fix-a-typo-in-an-error-about-size-with-bounded-ptr.patch/i386-gen.c 2012-03-06 00:19:03 +0000 |
4668 | +++ .pc/0002-Fix-a-typo-in-an-error-about-size-with-bounded-ptr.patch/i386-gen.c 1970-01-01 00:00:00 +0000 |
4669 | @@ -1,1089 +0,0 @@ |
4670 | -/* |
4671 | - * X86 code generator for TCC |
4672 | - * |
4673 | - * Copyright (c) 2001-2004 Fabrice Bellard |
4674 | - * |
4675 | - * This library is free software; you can redistribute it and/or |
4676 | - * modify it under the terms of the GNU Lesser General Public |
4677 | - * License as published by the Free Software Foundation; either |
4678 | - * version 2 of the License, or (at your option) any later version. |
4679 | - * |
4680 | - * This library is distributed in the hope that it will be useful, |
4681 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
4682 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
4683 | - * Lesser General Public License for more details. |
4684 | - * |
4685 | - * You should have received a copy of the GNU Lesser General Public |
4686 | - * License along with this library; if not, write to the Free Software |
4687 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
4688 | - */ |
4689 | - |
4690 | -#ifdef TARGET_DEFS_ONLY |
4691 | - |
4692 | -/* number of available registers */ |
4693 | -#define NB_REGS 4 |
4694 | -#define NB_ASM_REGS 8 |
4695 | - |
4696 | -/* a register can belong to several classes. The classes must be |
4697 | - sorted from more general to more precise (see gv2() code which does |
4698 | - assumptions on it). */ |
4699 | -#define RC_INT 0x0001 /* generic integer register */ |
4700 | -#define RC_FLOAT 0x0002 /* generic float register */ |
4701 | -#define RC_EAX 0x0004 |
4702 | -#define RC_ST0 0x0008 |
4703 | -#define RC_ECX 0x0010 |
4704 | -#define RC_EDX 0x0020 |
4705 | -#define RC_IRET RC_EAX /* function return: integer register */ |
4706 | -#define RC_LRET RC_EDX /* function return: second integer register */ |
4707 | -#define RC_FRET RC_ST0 /* function return: float register */ |
4708 | - |
4709 | -/* pretty names for the registers */ |
4710 | -enum { |
4711 | - TREG_EAX = 0, |
4712 | - TREG_ECX, |
4713 | - TREG_EDX, |
4714 | - TREG_ST0, |
4715 | -}; |
4716 | - |
4717 | -/* return registers for function */ |
4718 | -#define REG_IRET TREG_EAX /* single word int return register */ |
4719 | -#define REG_LRET TREG_EDX /* second word return register (for long long) */ |
4720 | -#define REG_FRET TREG_ST0 /* float return register */ |
4721 | - |
4722 | -/* defined if function parameters must be evaluated in reverse order */ |
4723 | -#define INVERT_FUNC_PARAMS |
4724 | - |
4725 | -/* defined if structures are passed as pointers. Otherwise structures |
4726 | - are directly pushed on stack. */ |
4727 | -//#define FUNC_STRUCT_PARAM_AS_PTR |
4728 | - |
4729 | -/* pointer size, in bytes */ |
4730 | -#define PTR_SIZE 4 |
4731 | - |
4732 | -/* long double size and alignment, in bytes */ |
4733 | -#define LDOUBLE_SIZE 12 |
4734 | -#define LDOUBLE_ALIGN 4 |
4735 | -/* maximum alignment (for aligned attribute support) */ |
4736 | -#define MAX_ALIGN 8 |
4737 | - |
4738 | - |
4739 | -#define psym oad |
4740 | - |
4741 | -/******************************************************/ |
4742 | -/* ELF defines */ |
4743 | - |
4744 | -#define EM_TCC_TARGET EM_386 |
4745 | - |
4746 | -/* relocation type for 32 bit data relocation */ |
4747 | -#define R_DATA_32 R_386_32 |
4748 | -#define R_DATA_PTR R_386_32 |
4749 | -#define R_JMP_SLOT R_386_JMP_SLOT |
4750 | -#define R_COPY R_386_COPY |
4751 | - |
4752 | -#define ELF_START_ADDR 0x08048000 |
4753 | -#define ELF_PAGE_SIZE 0x1000 |
4754 | - |
4755 | -/******************************************************/ |
4756 | -#else /* ! TARGET_DEFS_ONLY */ |
4757 | -/******************************************************/ |
4758 | -#include "tcc.h" |
4759 | - |
4760 | -ST_DATA const int reg_classes[NB_REGS] = { |
4761 | - /* eax */ RC_INT | RC_EAX, |
4762 | - /* ecx */ RC_INT | RC_ECX, |
4763 | - /* edx */ RC_INT | RC_EDX, |
4764 | - /* st0 */ RC_FLOAT | RC_ST0, |
4765 | -}; |
4766 | - |
4767 | -static unsigned long func_sub_sp_offset; |
4768 | -static int func_ret_sub; |
4769 | -#ifdef CONFIG_TCC_BCHECK |
4770 | -static unsigned long func_bound_offset; |
4771 | -#endif |
4772 | - |
4773 | -/* XXX: make it faster ? */ |
4774 | -ST_FUNC void g(int c) |
4775 | -{ |
4776 | - int ind1; |
4777 | - ind1 = ind + 1; |
4778 | - if (ind1 > cur_text_section->data_allocated) |
4779 | - section_realloc(cur_text_section, ind1); |
4780 | - cur_text_section->data[ind] = c; |
4781 | - ind = ind1; |
4782 | -} |
4783 | - |
4784 | -ST_FUNC void o(unsigned int c) |
4785 | -{ |
4786 | - while (c) { |
4787 | - g(c); |
4788 | - c = c >> 8; |
4789 | - } |
4790 | -} |
4791 | - |
4792 | -ST_FUNC void gen_le16(int v) |
4793 | -{ |
4794 | - g(v); |
4795 | - g(v >> 8); |
4796 | -} |
4797 | - |
4798 | -ST_FUNC void gen_le32(int c) |
4799 | -{ |
4800 | - g(c); |
4801 | - g(c >> 8); |
4802 | - g(c >> 16); |
4803 | - g(c >> 24); |
4804 | -} |
4805 | - |
4806 | -/* output a symbol and patch all calls to it */ |
4807 | -ST_FUNC void gsym_addr(int t, int a) |
4808 | -{ |
4809 | - int n, *ptr; |
4810 | - while (t) { |
4811 | - ptr = (int *)(cur_text_section->data + t); |
4812 | - n = *ptr; /* next value */ |
4813 | - *ptr = a - t - 4; |
4814 | - t = n; |
4815 | - } |
4816 | -} |
4817 | - |
4818 | -ST_FUNC void gsym(int t) |
4819 | -{ |
4820 | - gsym_addr(t, ind); |
4821 | -} |
4822 | - |
4823 | -/* psym is used to put an instruction with a data field which is a |
4824 | - reference to a symbol. It is in fact the same as oad ! */ |
4825 | -#define psym oad |
4826 | - |
4827 | -/* instruction + 4 bytes data. Return the address of the data */ |
4828 | -ST_FUNC int oad(int c, int s) |
4829 | -{ |
4830 | - int ind1; |
4831 | - |
4832 | - o(c); |
4833 | - ind1 = ind + 4; |
4834 | - if (ind1 > cur_text_section->data_allocated) |
4835 | - section_realloc(cur_text_section, ind1); |
4836 | - *(int *)(cur_text_section->data + ind) = s; |
4837 | - s = ind; |
4838 | - ind = ind1; |
4839 | - return s; |
4840 | -} |
4841 | - |
4842 | -/* output constant with relocation if 'r & VT_SYM' is true */ |
4843 | -ST_FUNC void gen_addr32(int r, Sym *sym, int c) |
4844 | -{ |
4845 | - if (r & VT_SYM) |
4846 | - greloc(cur_text_section, sym, ind, R_386_32); |
4847 | - gen_le32(c); |
4848 | -} |
4849 | - |
4850 | -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) |
4851 | -{ |
4852 | - if (r & VT_SYM) |
4853 | - greloc(cur_text_section, sym, ind, R_386_PC32); |
4854 | - gen_le32(c - 4); |
4855 | -} |
4856 | - |
4857 | -/* generate a modrm reference. 'op_reg' contains the addtionnal 3 |
4858 | - opcode bits */ |
4859 | -static void gen_modrm(int op_reg, int r, Sym *sym, int c) |
4860 | -{ |
4861 | - op_reg = op_reg << 3; |
4862 | - if ((r & VT_VALMASK) == VT_CONST) { |
4863 | - /* constant memory reference */ |
4864 | - o(0x05 | op_reg); |
4865 | - gen_addr32(r, sym, c); |
4866 | - } else if ((r & VT_VALMASK) == VT_LOCAL) { |
4867 | - /* currently, we use only ebp as base */ |
4868 | - if (c == (char)c) { |
4869 | - /* short reference */ |
4870 | - o(0x45 | op_reg); |
4871 | - g(c); |
4872 | - } else { |
4873 | - oad(0x85 | op_reg, c); |
4874 | - } |
4875 | - } else { |
4876 | - g(0x00 | op_reg | (r & VT_VALMASK)); |
4877 | - } |
4878 | -} |
4879 | - |
4880 | -/* load 'r' from value 'sv' */ |
4881 | -ST_FUNC void load(int r, SValue *sv) |
4882 | -{ |
4883 | - int v, t, ft, fc, fr; |
4884 | - SValue v1; |
4885 | - |
4886 | -#ifdef TCC_TARGET_PE |
4887 | - SValue v2; |
4888 | - sv = pe_getimport(sv, &v2); |
4889 | -#endif |
4890 | - |
4891 | - fr = sv->r; |
4892 | - ft = sv->type.t; |
4893 | - fc = sv->c.ul; |
4894 | - |
4895 | - v = fr & VT_VALMASK; |
4896 | - if (fr & VT_LVAL) { |
4897 | - if (v == VT_LLOCAL) { |
4898 | - v1.type.t = VT_INT; |
4899 | - v1.r = VT_LOCAL | VT_LVAL; |
4900 | - v1.c.ul = fc; |
4901 | - load(r, &v1); |
4902 | - fr = r; |
4903 | - } |
4904 | - if ((ft & VT_BTYPE) == VT_FLOAT) { |
4905 | - o(0xd9); /* flds */ |
4906 | - r = 0; |
4907 | - } else if ((ft & VT_BTYPE) == VT_DOUBLE) { |
4908 | - o(0xdd); /* fldl */ |
4909 | - r = 0; |
4910 | - } else if ((ft & VT_BTYPE) == VT_LDOUBLE) { |
4911 | - o(0xdb); /* fldt */ |
4912 | - r = 5; |
4913 | - } else if ((ft & VT_TYPE) == VT_BYTE) { |
4914 | - o(0xbe0f); /* movsbl */ |
4915 | - } else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED)) { |
4916 | - o(0xb60f); /* movzbl */ |
4917 | - } else if ((ft & VT_TYPE) == VT_SHORT) { |
4918 | - o(0xbf0f); /* movswl */ |
4919 | - } else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED)) { |
4920 | - o(0xb70f); /* movzwl */ |
4921 | - } else { |
4922 | - o(0x8b); /* movl */ |
4923 | - } |
4924 | - gen_modrm(r, fr, sv->sym, fc); |
4925 | - } else { |
4926 | - if (v == VT_CONST) { |
4927 | - o(0xb8 + r); /* mov $xx, r */ |
4928 | - gen_addr32(fr, sv->sym, fc); |
4929 | - } else if (v == VT_LOCAL) { |
4930 | - o(0x8d); /* lea xxx(%ebp), r */ |
4931 | - gen_modrm(r, VT_LOCAL, sv->sym, fc); |
4932 | - } else if (v == VT_CMP) { |
4933 | - oad(0xb8 + r, 0); /* mov $0, r */ |
4934 | - o(0x0f); /* setxx %br */ |
4935 | - o(fc); |
4936 | - o(0xc0 + r); |
4937 | - } else if (v == VT_JMP || v == VT_JMPI) { |
4938 | - t = v & 1; |
4939 | - oad(0xb8 + r, t); /* mov $1, r */ |
4940 | - o(0x05eb); /* jmp after */ |
4941 | - gsym(fc); |
4942 | - oad(0xb8 + r, t ^ 1); /* mov $0, r */ |
4943 | - } else if (v != r) { |
4944 | - o(0x89); |
4945 | - o(0xc0 + r + v * 8); /* mov v, r */ |
4946 | - } |
4947 | - } |
4948 | -} |
4949 | - |
4950 | -/* store register 'r' in lvalue 'v' */ |
4951 | -ST_FUNC void store(int r, SValue *v) |
4952 | -{ |
4953 | - int fr, bt, ft, fc; |
4954 | - |
4955 | -#ifdef TCC_TARGET_PE |
4956 | - SValue v2; |
4957 | - v = pe_getimport(v, &v2); |
4958 | -#endif |
4959 | - |
4960 | - ft = v->type.t; |
4961 | - fc = v->c.ul; |
4962 | - fr = v->r & VT_VALMASK; |
4963 | - bt = ft & VT_BTYPE; |
4964 | - /* XXX: incorrect if float reg to reg */ |
4965 | - if (bt == VT_FLOAT) { |
4966 | - o(0xd9); /* fsts */ |
4967 | - r = 2; |
4968 | - } else if (bt == VT_DOUBLE) { |
4969 | - o(0xdd); /* fstpl */ |
4970 | - r = 2; |
4971 | - } else if (bt == VT_LDOUBLE) { |
4972 | - o(0xc0d9); /* fld %st(0) */ |
4973 | - o(0xdb); /* fstpt */ |
4974 | - r = 7; |
4975 | - } else { |
4976 | - if (bt == VT_SHORT) |
4977 | - o(0x66); |
4978 | - if (bt == VT_BYTE || bt == VT_BOOL) |
4979 | - o(0x88); |
4980 | - else |
4981 | - o(0x89); |
4982 | - } |
4983 | - if (fr == VT_CONST || |
4984 | - fr == VT_LOCAL || |
4985 | - (v->r & VT_LVAL)) { |
4986 | - gen_modrm(r, v->r, v->sym, fc); |
4987 | - } else if (fr != r) { |
4988 | - o(0xc0 + fr + r * 8); /* mov r, fr */ |
4989 | - } |
4990 | -} |
4991 | - |
4992 | -static void gadd_sp(int val) |
4993 | -{ |
4994 | - if (val == (char)val) { |
4995 | - o(0xc483); |
4996 | - g(val); |
4997 | - } else { |
4998 | - oad(0xc481, val); /* add $xxx, %esp */ |
4999 | - } |
5000 | -} |
The diff has been truncated for viewing.
Hi Liu
Thanks for preparing this merge proposal.
In order to update versions of packages in released versions of Ubuntu, updates must follow the Ubuntu Stable Release Update process as detailed here:
https:/ /wiki.ubuntu. com/StableRelea seUpdates
This MP is an extremely large diff against the version in precise so won't be accepted; Please take some time to review the process. You will also need a bug, to have fixed it in the current development release and to have documented a testing process so that the fix can be verified once in -proposed.
Marking 'Needs Fixing' and WIP for the time being.
Thanks!