source: mainline/uspace/app/pcc/arch/arm/local.c@ a7de7182

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a7de7182 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 20.2 KB
Line 
1/* $Id: local.c,v 1.24 2011/01/21 21:47:58 ragge Exp $ */
2/*
3 * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org).
4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * We define location operations which operate on the expression tree
32 * during the first pass (before sending to the backend for code generation.)
33 */
34
35#include <assert.h>
36
37#include "pass1.h"
38
39extern void defalign(int);
40
41/*
42 * clocal() is called to do local transformations on
43 * an expression tree before being sent to the backend.
44 */
45NODE *
46clocal(NODE *p)
47{
48 struct symtab *q;
49 NODE *l, *r, *t;
50 int o;
51 int ty;
52 int tmpnr, isptrvoid = 0;
53 char *n;
54
55 o = p->n_op;
56 switch (o) {
57
58 case STASG:
59
60 l = p->n_left;
61 r = p->n_right;
62 if (r->n_op != STCALL && r->n_op != USTCALL)
63 return p;
64
65 /* assign left node as first argument to function */
66 nfree(p);
67 t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_sue);
68 l->n_rval = R0;
69 l = buildtree(ADDROF, l, NIL);
70 l = buildtree(ASSIGN, t, l);
71
72 if (r->n_right->n_op != CM) {
73 r->n_right = block(CM, l, r->n_right,
74 INT, 0, MKSUE(INT));
75 } else {
76 for (t = r->n_right; t->n_left->n_op == CM;
77 t = t->n_left)
78 ;
79 t->n_left = block(CM, l, t->n_left,
80 INT, 0, MKSUE(INT));
81 }
82 return r;
83
84 case CALL:
85 case STCALL:
86 case USTCALL:
87 if (p->n_type == VOID)
88 break;
89 /*
90 * if the function returns void*, ecode() invokes
91 * delvoid() to convert it to uchar*.
92 * We just let this happen on the ASSIGN to the temp,
93 * and cast the pointer back to void* on access
94 * from the temp.
95 */
96 if (p->n_type == PTR+VOID)
97 isptrvoid = 1;
98 r = tempnode(0, p->n_type, p->n_df, p->n_sue);
99 tmpnr = regno(r);
100 r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_sue);
101
102 p = tempnode(tmpnr, r->n_type, r->n_df, r->n_sue);
103 if (isptrvoid) {
104 p = block(PCONV, p, NIL, PTR+VOID,
105 p->n_df, MKSUE(PTR+VOID));
106 }
107 p = buildtree(COMOP, r, p);
108 break;
109
110 case NAME:
111 if ((q = p->n_sp) == NULL)
112 return p;
113 if (blevel == 0)
114 return p;
115
116 switch (q->sclass) {
117 case PARAM:
118 case AUTO:
119 /* fake up a structure reference */
120 r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
121 r->n_lval = 0;
122 r->n_rval = FPREG;
123 p = stref(block(STREF, r, p, 0, 0, 0));
124 break;
125 case REGISTER:
126 p->n_op = REG;
127 p->n_lval = 0;
128 p->n_rval = q->soffset;
129 break;
130 case STATIC:
131 if (q->slevel > 0) {
132 p->n_lval = 0;
133 p->n_sp = q;
134 }
135 /* FALL-THROUGH */
136 default:
137 ty = p->n_type;
138 n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname;
139 if (strncmp(n, "__builtin", 9) == 0)
140 break;
141 p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_sue);
142 p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
143 break;
144 }
145 break;
146
147 case STNAME:
148 if ((q = p->n_sp) == NULL)
149 return p;
150 if (q->sclass != STNAME)
151 return p;
152 ty = p->n_type;
153 p = block(ADDROF, p, NIL, INCREF(ty),
154 p->n_df, p->n_sue);
155 p = block(UMUL, p, NIL, ty, p->n_df, p->n_sue);
156 break;
157
158 case FORCE:
159 /* put return value in return reg */
160 p->n_op = ASSIGN;
161 p->n_right = p->n_left;
162 p->n_left = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
163 p->n_left->n_rval = p->n_left->n_type == BOOL ?
164 RETREG(BOOL_TYPE) : RETREG(p->n_type);
165 break;
166
167 case PMCONV:
168 case PVCONV:
169 nfree(p);
170 return buildtree(o == PMCONV ? MUL : DIV, p->n_left, p->n_right);
171
172 case SCONV:
173 l = p->n_left;
174 if (p->n_type == l->n_type) {
175 nfree(p);
176 return l;
177 }
178 if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
179 btdims[p->n_type].suesize == btdims[l->n_type].suesize) {
180 if (p->n_type != FLOAT && p->n_type != DOUBLE &&
181 l->n_type != FLOAT && l->n_type != DOUBLE &&
182 l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
183 if (l->n_op == NAME || l->n_op == UMUL ||
184 l->n_op == TEMP) {
185 l->n_type = p->n_type;
186 nfree(p);
187 return l;
188 }
189 }
190 }
191
192 if (l->n_op == ICON) {
193 CONSZ val = l->n_lval;
194
195 if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */
196 switch (p->n_type) {
197 case BOOL:
198 l->n_lval = l->n_lval != 0;
199 break;
200 case CHAR:
201 l->n_lval = (char)val;
202 break;
203 case UCHAR:
204 l->n_lval = val & 0377;
205 break;
206 case SHORT:
207 l->n_lval = (short)val;
208 break;
209 case USHORT:
210 l->n_lval = val & 0177777;
211 break;
212 case ULONG:
213 case UNSIGNED:
214 l->n_lval = val & 0xffffffff;
215 break;
216 case LONG:
217 case INT:
218 l->n_lval = (int)val;
219 break;
220 case LONGLONG:
221 l->n_lval = (long long)val;
222 break;
223 case ULONGLONG:
224 l->n_lval = val;
225 break;
226 case VOID:
227 break;
228 case LDOUBLE:
229 case DOUBLE:
230 case FLOAT:
231 l->n_op = FCON;
232 l->n_dcon = val;
233 break;
234 default:
235 cerror("unknown type %d", l->n_type);
236 }
237 l->n_type = p->n_type;
238 l->n_sue = MKSUE(p->n_type);
239 nfree(p);
240 return l;
241 } else if (p->n_op == FCON) {
242 l->n_lval = l->n_dcon;
243 l->n_sp = NULL;
244 l->n_op = ICON;
245 l->n_type = p->n_type;
246 l->n_sue = MKSUE(p->n_type);
247 nfree(p);
248 return clocal(l);
249 }
250 if ((DEUNSIGN(p->n_type) == CHAR ||
251 DEUNSIGN(p->n_type) == SHORT) &&
252 (l->n_type == FLOAT || l->n_type == DOUBLE ||
253 l->n_type == LDOUBLE)) {
254 p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue);
255 p->n_left->n_type = INT;
256 return p;
257 }
258 break;
259
260 case PCONV:
261 l = p->n_left;
262 if (l->n_op == ICON) {
263 l->n_lval = (unsigned)l->n_lval;
264 goto delp;
265 }
266 if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) {
267 p->n_left = block(SCONV, l, NIL,
268 UNSIGNED, 0, MKSUE(UNSIGNED));
269 break;
270 }
271 if (l->n_op == SCONV)
272 break;
273 if (l->n_op == ADDROF && l->n_left->n_op == TEMP)
274 goto delp;
275 if (p->n_type > BTMASK && l->n_type > BTMASK)
276 goto delp;
277 break;
278
279 delp:
280 l->n_type = p->n_type;
281 l->n_qual = p->n_qual;
282 l->n_df = p->n_df;
283 l->n_sue = p->n_sue;
284 nfree(p);
285 p = l;
286 break;
287 }
288
289 return p;
290}
291
292/*
293 * Called before sending the tree to the backend.
294 */
295void
296myp2tree(NODE *p)
297{
298 struct symtab *sp;
299
300 if (p->n_op != FCON)
301 return;
302
303#define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz))
304
305 sp = IALLOC(sizeof(struct symtab));
306 sp->sclass = STATIC;
307 sp->ssue = MKSUE(p->n_type);
308 sp->slevel = 1; /* fake numeric label */
309 sp->soffset = getlab();
310 sp->sflags = 0;
311 sp->stype = p->n_type;
312 sp->squal = (CON >> TSHIFT);
313
314 defloc(sp);
315 ninval(0, sp->ssue->suesize, p);
316
317 p->n_op = NAME;
318 p->n_lval = 0;
319 p->n_sp = sp;
320
321}
322
323/*
324 * Called during the first pass to determine if a NAME can be addressed.
325 *
326 * Return nonzero if supported, otherwise return 0.
327 */
328int
329andable(NODE *p)
330{
331 if (blevel == 0)
332 return 1;
333 if (ISFTN(p->n_type))
334 return 1;
335 return 0;
336}
337
338/*
339 * Called just after function arguments are built. Re-initialize the
340 * offset of the arguments on the stack.
341 * Is this necessary anymore? bfcode() is called immediately after.
342 */
343void
344cendarg()
345{
346 autooff = AUTOINIT;
347}
348
349/*
350 * Return 1 if a variable of type 't' is OK to put in register.
351 */
352int
353cisreg(TWORD t)
354{
355 if (t == FLOAT || t == DOUBLE || t == LDOUBLE)
356 return 0; /* not yet */
357 return 1;
358}
359
360/*
361 * Used for generating pointer offsets into structures and arrays.
362 *
363 * For a pointer of type 't', generate an the offset 'off'.
364 */
365NODE *
366offcon(OFFSZ off, TWORD t, union dimfun *d, struct suedef *sue)
367{
368 return bcon(off/SZCHAR);
369}
370
371/*
372 * Allocate bits from the stack for dynamic-sized arrays.
373 *
374 * 'p' is the tree which represents the type being allocated.
375 * 'off' is the number of 'p's to be allocated.
376 * 't' is the storeable node where the address is written.
377 */
378void
379spalloc(NODE *t, NODE *p, OFFSZ off)
380{
381 NODE *sp;
382
383 p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */
384
385 /* sub the size from sp */
386 sp = block(REG, NIL, NIL, p->n_type, 0, MKSUE(INT));
387 sp->n_lval = 0;
388 sp->n_rval = SP;
389 ecomp(buildtree(MINUSEQ, sp, p));
390
391 /* save the address of sp */
392 sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue);
393 sp->n_lval = 0;
394 sp->n_rval = SP;
395 t->n_type = sp->n_type;
396 ecomp(buildtree(ASSIGN, t, sp));
397}
398
399/*
400 * Print out a string of characters.
401 * Assume that the assembler understands C-style escape
402 * sequences.
403 */
404void
405instring(struct symtab *sp)
406{
407 char *s, *str;
408
409 defloc(sp);
410 str = sp->sname;
411
412 /* be kind to assemblers and avoid long strings */
413 printf("\t.ascii \"");
414 for (s = str; *s != 0; ) {
415 if (*s++ == '\\') {
416 (void)esccon(&s);
417 }
418 if (s - str > 60) {
419 fwrite(str, 1, s - str, stdout);
420 printf("\"\n\t.ascii \"");
421 str = s;
422 }
423 }
424 fwrite(str, 1, s - str, stdout);
425 printf("\\0\"\n");
426}
427
428static int inbits = 0, inval = 0;
429
430/*
431 * set 'fsz' bits in sequence to zero.
432 */
433void
434zbits(OFFSZ off, int fsz)
435{
436 int m;
437
438 if (idebug)
439 printf("zbits off %lld, fsz %d inbits %d\n", off, fsz, inbits);
440 if ((m = (inbits % SZCHAR))) {
441 m = SZCHAR - m;
442 if (fsz < m) {
443 inbits += fsz;
444 return;
445 } else {
446 fsz -= m;
447 printf("\t.byte %d\n", inval);
448 inval = inbits = 0;
449 }
450 }
451 if (fsz >= SZCHAR) {
452 printf("\t.space %d\n", fsz/SZCHAR);
453 fsz -= (fsz/SZCHAR) * SZCHAR;
454 }
455 if (fsz) {
456 inval = 0;
457 inbits = fsz;
458 }
459}
460
461/*
462 * Initialize a bitfield.
463 */
464void
465infld(CONSZ off, int fsz, CONSZ val)
466{
467 if (idebug)
468 printf("infld off %lld, fsz %d, val %lld inbits %d\n",
469 off, fsz, val, inbits);
470 val &= (1 << fsz)-1;
471 while (fsz + inbits >= SZCHAR) {
472 inval |= (val << inbits);
473 printf("\t.byte %d\n", inval & 255);
474 fsz -= (SZCHAR - inbits);
475 val >>= (SZCHAR - inbits);
476 inval = inbits = 0;
477 }
478 if (fsz) {
479 inval |= (val << inbits);
480 inbits += fsz;
481 }
482}
483
484/*
485 * Print an integer constant node, may be associated with a label.
486 * Do not free the node after use.
487 * 'off' is bit offset from the beginning of the aggregate
488 * 'fsz' is the number of bits this is referring to
489 */
490void
491ninval(CONSZ off, int fsz, NODE *p)
492{
493 union { float f; double d; int i[2]; } u;
494 struct symtab *q;
495 TWORD t;
496 int i, j;
497
498 t = p->n_type;
499 if (t > BTMASK)
500 t = INT; /* pointer */
501
502 /*
503 * The target-independent code does rewrite the NAME nodes
504 * to ICONS after we prefixed the NAME nodes with ADDROF.
505 * We do it here. Maybe this is too much of a hack!
506 */
507 if (p->n_op == ADDROF && p->n_left->n_op == NAME) {
508 p = p->n_left;
509 p->n_op = ICON;
510 }
511
512 if (p->n_op != ICON && p->n_op != FCON)
513 cerror("ninval: init node not constant: node %p", p);
514
515 if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT)
516 uerror("element not constant");
517
518 switch (t) {
519 case LONGLONG:
520 case ULONGLONG:
521 i = (p->n_lval >> 32);
522 j = (p->n_lval & 0xffffffff);
523 p->n_type = INT;
524 if (features(FEATURE_BIGENDIAN)) {
525 p->n_lval = i;
526 ninval(off+32, 32, p);
527 p->n_lval = j;
528 ninval(off, 32, p);
529 } else {
530 p->n_lval = j;
531 ninval(off, 32, p);
532 p->n_lval = i;
533 ninval(off+32, 32, p);
534 }
535 break;
536 case INT:
537 case UNSIGNED:
538 printf("\t.word 0x%x", (int)p->n_lval);
539 if ((q = p->n_sp) != NULL) {
540 if ((q->sclass == STATIC && q->slevel > 0)) {
541 printf("+" LABFMT, q->soffset);
542 } else
543 printf("+%s",
544 q->soname ? q->soname : exname(q->sname));
545 }
546 printf("\n");
547 break;
548 case SHORT:
549 case USHORT:
550 printf("\t.short 0x%x\n", (int)p->n_lval & 0xffff);
551 break;
552 case BOOL:
553 if (p->n_lval > 1)
554 p->n_lval = p->n_lval != 0;
555 /* FALLTHROUGH */
556 case CHAR:
557 case UCHAR:
558 printf("\t.byte %d\n", (int)p->n_lval & 0xff);
559 break;
560 case LDOUBLE:
561 case DOUBLE:
562 u.d = (double)p->n_dcon;
563#if defined(HOST_BIG_ENDIAN)
564 if (features(FEATURE_BIGENDIAN))
565#else
566 if (!features(FEATURE_BIGENDIAN))
567#endif
568 printf("\t.word\t0x%x\n\t.word\t0x%x\n",
569 u.i[0], u.i[1]);
570 else
571 printf("\t.word\t0x%x\n\t.word\t0x%x\n",
572 u.i[1], u.i[0]);
573 break;
574 case FLOAT:
575 u.f = (float)p->n_dcon;
576 printf("\t.word\t0x%x\n", u.i[0]);
577 break;
578 default:
579 cerror("ninval");
580 }
581}
582
583/*
584 * Prefix a leading underscore to a global variable (if necessary).
585 */
586char *
587exname(char *p)
588{
589 return (p == NULL ? "" : p);
590}
591
592/*
593 * Map types which are not defined on the local machine.
594 */
595TWORD
596ctype(TWORD type)
597{
598 switch (BTYPE(type)) {
599 case LONG:
600 MODTYPE(type,INT);
601 break;
602 case ULONG:
603 MODTYPE(type,UNSIGNED);
604 break;
605 }
606 return (type);
607}
608
609/*
610 * Before calling a function do any tree re-writing for the local machine.
611 *
612 * 'p' is the function tree (NAME)
613 * 'q' is the CM-separated list of arguments.
614 */
615void
616calldec(NODE *p, NODE *q)
617{
618}
619
620/*
621 * While handling uninitialised variables, handle variables marked extern.
622 */
623void
624extdec(struct symtab *q)
625{
626}
627
628/* make a common declaration for id, if reasonable */
629void
630defzero(struct symtab *sp)
631{
632 int off;
633
634 off = tsize(sp->stype, sp->sdf, sp->ssue);
635 off = (off+(SZCHAR-1))/SZCHAR;
636 printf(" .%scomm ", sp->sclass == STATIC ? "l" : "");
637 if (sp->slevel == 0)
638 printf("%s,0%o\n",
639 sp->soname ? sp->soname : exname(sp->sname), off);
640 else
641 printf(LABFMT ",0%o\n", sp->soffset, off);
642}
643
644/*
645 * va_start(ap, last) implementation.
646 *
647 * f is the NAME node for this builtin function.
648 * a is the argument list containing:
649 * CM
650 * ap last
651 */
652NODE *
653arm_builtin_stdarg_start(NODE *f, NODE *a)
654{
655 NODE *p, *q;
656 int sz = 1;
657
658 /* check num args and type */
659 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
660 !ISPTR(a->n_left->n_type))
661 goto bad;
662
663 /* must first deal with argument size; use int size */
664 p = a->n_right;
665 if (p->n_type < INT) {
666 /* round up to word */
667 sz = SZINT / tsize(p->n_type, p->n_df, p->n_sue);
668 }
669
670 p = buildtree(ADDROF, p, NIL); /* address of last arg */
671 p = optim(buildtree(PLUS, p, bcon(sz)));
672 q = block(NAME, NIL, NIL, PTR+VOID, 0, 0);
673 q = buildtree(CAST, q, p);
674 p = q->n_right;
675 nfree(q->n_left);
676 nfree(q);
677 p = buildtree(ASSIGN, a->n_left, p);
678 tfree(f);
679 nfree(a);
680
681 return p;
682
683bad:
684 uerror("bad argument to __builtin_stdarg_start");
685 return bcon(0);
686}
687
688NODE *
689arm_builtin_va_arg(NODE *f, NODE *a)
690{
691 NODE *p, *q, *r;
692 int sz, tmpnr;
693
694 /* check num args and type */
695 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM ||
696 !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE)
697 goto bad;
698
699 r = a->n_right;
700
701 /* get type size */
702 sz = tsize(r->n_type, r->n_df, r->n_sue) / SZCHAR;
703 if (sz < SZINT/SZCHAR) {
704 werror("%s%s promoted to int when passed through ...",
705 ISUNSIGNED(r->n_type) ? "unsigned " : "",
706 DEUNSIGN(r->n_type) == SHORT ? "short" : "char");
707 sz = SZINT/SZCHAR;
708 }
709
710 /* alignment */
711 p = tcopy(a->n_left);
712 if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) {
713 p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1));
714 p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_sue);
715 }
716
717 /* create a copy to a temp node */
718 q = tempnode(0, p->n_type, p->n_df, p->n_sue);
719 tmpnr = regno(q);
720 p = buildtree(ASSIGN, q, p);
721
722 q = tempnode(tmpnr, p->n_type, p->n_df,p->n_sue);
723 q = buildtree(PLUS, q, bcon(sz));
724 q = buildtree(ASSIGN, a->n_left, q);
725
726 q = buildtree(COMOP, p, q);
727
728 nfree(a->n_right);
729 nfree(a);
730 nfree(f);
731
732 p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_sue);
733 p = buildtree(UMUL, p, NIL);
734 p = buildtree(COMOP, q, p);
735
736 return p;
737
738bad:
739 uerror("bad argument to __builtin_va_arg");
740 return bcon(0);
741}
742
743NODE *
744arm_builtin_va_end(NODE *f, NODE *a)
745{
746 tfree(f);
747 tfree(a);
748
749 return bcon(0);
750}
751
752NODE *
753arm_builtin_va_copy(NODE *f, NODE *a)
754{
755 if (a == NULL || a->n_op != CM || a->n_left->n_op == CM)
756 goto bad;
757 tfree(f);
758 f = buildtree(ASSIGN, a->n_left, a->n_right);
759 nfree(a);
760 return f;
761
762bad:
763 uerror("bad argument to __buildtin_va_copy");
764 return bcon(0);
765}
766
767char *nextsect;
768static int constructor;
769static int destructor;
770
771/*
772 * Give target the opportunity of handling pragmas.
773 */
774int
775mypragma(char *str)
776{
777 char *a2 = pragtok(NULL);
778
779 if (strcmp(str, "tls") == 0) {
780 uerror("thread-local storage not supported for this target");
781 return 1;
782 }
783 if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
784 constructor = 1;
785 return 1;
786 }
787 if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
788 destructor = 1;
789 return 1;
790 }
791 if (strcmp(str, "section") || s2 == NULL)
792 return 0;
793 nextsect = newstring(s2, strlen(s2));
794 return 1;
795}
796
797/*
798 * Called when a identifier has been declared, to give target last word.
799 */
800void
801fixdef(struct symtab *sp)
802{
803 if ((constructor || destructor) && (sp->sclass != PARAM)) {
804 printf("\t.section .%ctors,\"aw\",@progbits\n",
805 constructor ? 'c' : 'd');
806 printf("\t.p2align 2\n");
807 printf("\t.long %s\n", exname(sp->sname));
808 printf("\t.previous\n");
809 constructor = destructor = 0;
810 }
811}
812
813void
814pass1_lastchance(struct interpass *ip)
815{
816}
Note: See TracBrowser for help on using the repository browser.