1/*	Id: local.c,v 1.66 2012/03/23 17:03:09 ragge Exp 	*/
2/*	$NetBSD: local.c,v 1.1.1.3.4.1 2012/04/03 16:36:21 riz Exp $	*/
3/*
4 * Copyright (c) 2008 Michael Shalayeff
5 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29
30#include "pass1.h"
31
32/*	this file contains code which is dependent on the target machine */
33
34/*
35 * Check if a constant is too large for a type.
36 */
37#ifdef notyet
38static int
39toolarge(TWORD t, CONSZ con)
40{
41	U_CONSZ ucon = con;
42
43	switch (t) {
44	case ULONG:
45	case LONG:
46	case ULONGLONG:
47	case LONGLONG:
48		break; /* cannot be too large */
49#define	SCHK(i)	case i: if (con > MAX_##i || con < MIN_##i) return 1; break
50#define	UCHK(i)	case i: if (ucon > MAX_##i) return 1; break
51	SCHK(INT);
52	SCHK(SHORT);
53	case BOOL:
54	SCHK(CHAR);
55	UCHK(UNSIGNED);
56	UCHK(USHORT);
57	UCHK(UCHAR);
58	default:
59		cerror("toolarge");
60	}
61	return 0;
62}
63#endif
64
65#define	IALLOC(sz)	(isinlining ? permalloc(sz) : tmpalloc(sz))
66
67/*
68 * Make a symtab entry for PIC use.
69 */
70static struct symtab *
71picsymtab(char *p, char *s, char *s2)
72{
73	struct symtab *sp = IALLOC(sizeof(struct symtab));
74	size_t len = strlen(p) + strlen(s) + strlen(s2) + 1;
75
76	sp->sname = sp->soname = IALLOC(len);
77	strlcpy(sp->soname, p, len);
78	strlcat(sp->soname, s, len);
79	strlcat(sp->soname, s2, len);
80	sp->sclass = EXTERN;
81	sp->sflags = sp->slevel = 0;
82	return sp;
83}
84
85int gotnr; /* tempnum for GOT register */
86int argstacksize;
87
88/*
89 * Create a reference for an extern variable or function.
90 */
91static NODE *
92picext(NODE *p)
93{
94#if defined(ELFABI)
95
96	NODE *q;
97	struct symtab *sp;
98	char *c;
99
100	if (p->n_sp->sflags & SBEENHERE)
101		return p;
102
103	c = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname);
104	sp = picsymtab("", c, "@GOTPCREL");
105	sp->sflags |= SBEENHERE;
106	q = block(NAME, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap);
107	q->n_sp = sp;
108	q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap);
109	q->n_sp = sp;
110	nfree(p);
111	return q;
112
113#elif defined(MACHOABI)
114
115	return p;
116
117#endif
118}
119
120static NODE *
121cmop(NODE *l, NODE *r)
122{
123	return block(CM, l, r, INT, 0, 0);
124}
125
126static NODE *
127mkx(char *s, NODE *p)
128{
129	p = block(XARG, p, NIL, INT, 0, 0);
130	p->n_name = s;
131	return p;
132}
133
134static char *
135mk3str(char *s1, char *s2, char *s3)
136{
137	int len = strlen(s1) + strlen(s2) + strlen(s3) + 1;
138	char *sd;
139
140	sd = inlalloc(len);
141	strlcpy(sd, s1, len);
142	strlcat(sd, s2, len);
143	strlcat(sd, s3, len);
144	return sd;
145}
146
147/*
148 * Create a reference for a TLS variable.
149 * This is the "General dynamic" version.
150 */
151static NODE *
152tlspic(NODE *p)
153{
154	NODE *q, *r, *s;
155	char *s1, *s2;
156
157	/*
158	 * .byte   0x66
159	 * leaq x@TLSGD(%rip),%rdi
160	 * .word   0x6666
161	 * rex64
162	 * call __tls_get_addr@PLT
163	 */
164
165	/* Need the .byte stuff around.  Why? */
166	/* Use inline assembler */
167	q = mkx("%rdx", bcon(0));
168	q = cmop(q, mkx("%rcx", bcon(0)));
169	q = cmop(q, mkx("%rsi", bcon(0)));
170	q = cmop(q, mkx("%rdi", bcon(0)));
171	q = cmop(q, mkx("%r8", bcon(0)));
172	q = cmop(q, mkx("%r9", bcon(0)));
173	q = cmop(q, mkx("%r10", bcon(0)));
174	q = cmop(q, mkx("%r11", bcon(0)));
175
176	s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
177	r = mkx("=a", r);
178	r = block(XASM, r, q, INT, 0, 0);
179
180	/* Create the magic string */
181	s1 = ".byte 0x66\n\tleaq ";
182	s2 = "@TLSGD(%%rip),%%rdi\n"
183	    "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT";
184	if (p->n_sp->soname == NULL)
185		p->n_sp->soname = p->n_sp->sname;
186	r->n_name = mk3str(s1, p->n_sp->soname, s2);
187
188	r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
189	r = buildtree(UMUL, r, NIL);
190	tfree(p);
191	return r;
192}
193
194/*
195 * The "initial exec" tls model.
196 */
197static NODE *
198tlsinitialexec(NODE *p)
199{
200	NODE *q, *r, *s;
201	char *s1, *s2;
202
203	/*
204	 * movq %fs:0,%rax
205	 * addq x@GOTTPOFF(%rip),%rax
206	 */
207
208	q = bcon(0);
209	q->n_type = STRTY;
210
211	s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap));
212	r = mkx("=r", r);
213	r = block(XASM, r, q, INT, 0, 0);
214
215	s1 = "movq %%fs:0,%0\n\taddq ";
216	s2 = "@GOTTPOFF(%%rip),%0";
217	if (p->n_sp->soname == NULL)
218		p->n_sp->soname = p->n_sp->sname;
219	r->n_name = mk3str(s1, p->n_sp->soname, s2);
220
221	r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap);
222	r = buildtree(UMUL, r, NIL);
223	tfree(p);
224	return r;
225}
226
227static NODE *
228tlsref(NODE *p)
229{
230	struct symtab *sp = p->n_sp;
231	struct attr *ga;
232	char *c;
233
234	if ((ga = attr_find(sp->sap, GCC_ATYP_TLSMODEL)) != NULL) {
235		c = ga->sarg(0);
236		if (strcmp(c, "initial-exec") == 0)
237			return tlsinitialexec(p);
238		else if (strcmp(c, "global-dynamic") == 0)
239			;
240		else
241			werror("unsupported tls model '%s'", c);
242	}
243	return tlspic(p);
244}
245
246/* clocal() is called to do local transformations on
247 * an expression tree preparitory to its being
248 * written out in intermediate code.
249 *
250 * the major essential job is rewriting the
251 * automatic variables and arguments in terms of
252 * REG and OREG nodes
253 * conversion ops which are not necessary are also clobbered here
254 * in addition, any special features (such as rewriting
255 * exclusive or) are easily handled here as well
256 */
257NODE *
258clocal(NODE *p)
259{
260
261	register struct symtab *q;
262	register NODE *r, *l;
263	register int o;
264	register int m;
265	TWORD t;
266
267#ifdef PCC_DEBUG
268	if (xdebug) {
269		printf("clocal: %p\n", p);
270		fwalk(p, eprint, 0);
271	}
272#endif
273	switch( o = p->n_op ){
274
275	case NAME:
276		if ((q = p->n_sp) == NULL)
277			return p; /* Nothing to care about */
278
279		switch (q->sclass) {
280
281		case PARAM:
282		case AUTO:
283			/* fake up a structure reference */
284			r = block(REG, NIL, NIL, PTR+STRTY, 0, 0);
285			r->n_lval = 0;
286			r->n_rval = FPREG;
287			p = stref(block(STREF, r, p, 0, 0, 0));
288			break;
289
290		case USTATIC:
291			if (kflag == 0)
292				break;
293			/* FALLTHROUGH */
294		case STATIC:
295#ifdef TLS
296			if (q->sflags & STLS) {
297				p = tlsref(p);
298				break;
299			}
300#endif
301			break;
302
303		case REGISTER:
304			p->n_op = REG;
305			p->n_lval = 0;
306			p->n_rval = q->soffset;
307			break;
308
309		case EXTERN:
310		case EXTDEF:
311			if (q->sflags & STLS) {
312				p = tlsref(p);
313				break;
314			}
315			if (kflag == 0 || statinit)
316				break;
317			if (blevel > 0)
318				p = picext(p);
319			break;
320		}
321		break;
322
323	case UCALL:
324	case USTCALL:
325		/* For now, always clear eax */
326		l = block(REG, NIL, NIL, INT, 0, 0);
327		regno(l) = RAX;
328		p->n_right = clocal(buildtree(ASSIGN, l, bcon(0)));
329		p->n_op -= (UCALL-CALL);
330		break;
331
332	case SCONV:
333		/* Special-case shifts */
334		if (p->n_type == LONG && (l = p->n_left)->n_op == LS &&
335		    l->n_type == INT && l->n_right->n_op == ICON) {
336			p->n_left = l->n_left;
337			p = buildtree(LS, p, l->n_right);
338			nfree(l);
339			break;
340		}
341
342		l = p->n_left;
343
344		/* Float conversions may need extra casts */
345		if (p->n_type == FLOAT || p->n_type == DOUBLE ||
346		    p->n_type == LDOUBLE) {
347			if (l->n_type < INT || l->n_type == BOOL) {
348				p->n_left = block(SCONV, l, NIL,
349				    ISUNSIGNED(l->n_type) ? UNSIGNED : INT,
350				    l->n_df, l->n_ap);
351				break;
352			}
353		}
354
355		if (p->n_type == l->n_type) {
356			nfree(p);
357			return l;
358		}
359
360		if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 &&
361		    tsize(p->n_type, p->n_df, p->n_ap) ==
362		    tsize(l->n_type, l->n_df, l->n_ap)) {
363			if (p->n_type != FLOAT && p->n_type != DOUBLE &&
364			    l->n_type != FLOAT && l->n_type != DOUBLE &&
365			    l->n_type != LDOUBLE && p->n_type != LDOUBLE) {
366				if (l->n_op == NAME || l->n_op == UMUL ||
367				    l->n_op == TEMP) {
368					l->n_type = p->n_type;
369					nfree(p);
370					return l;
371				}
372			}
373		}
374
375		if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT &&
376		    coptype(l->n_op) == BITYPE && l->n_op != COMOP &&
377		    l->n_op != QUEST) {
378			l->n_type = p->n_type;
379			nfree(p);
380			return l;
381		}
382
383		o = l->n_op;
384		m = p->n_type;
385
386		if (o == ICON) {
387			CONSZ val = l->n_lval;
388
389			if (!ISPTR(m)) /* Pointers don't need to be conv'd */
390			    switch (m) {
391			case BOOL:
392				l->n_lval = nncon(l) ? (l->n_lval != 0) : 1;
393				l->n_sp = NULL;
394				break;
395			case CHAR:
396				l->n_lval = (char)val;
397				break;
398			case UCHAR:
399				l->n_lval = val & 0377;
400				break;
401			case SHORT:
402				l->n_lval = (short)val;
403				break;
404			case USHORT:
405				l->n_lval = val & 0177777;
406				break;
407			case UNSIGNED:
408				l->n_lval = val & 0xffffffff;
409				break;
410			case INT:
411				l->n_lval = (int)val;
412				break;
413			case LONG:
414			case LONGLONG:
415				l->n_lval = (long long)val;
416				break;
417			case ULONG:
418			case ULONGLONG:
419				l->n_lval = val;
420				break;
421			case VOID:
422				break;
423			case LDOUBLE:
424			case DOUBLE:
425			case FLOAT:
426				l->n_op = FCON;
427				l->n_dcon = val;
428				break;
429			default:
430				cerror("unknown type %d", m);
431			}
432			l->n_type = m;
433			l->n_ap = NULL;
434			nfree(p);
435			return l;
436		} else if (l->n_op == FCON) {
437			if (p->n_type == BOOL)
438				l->n_lval = l->n_dcon != 0.0;
439			else
440				l->n_lval = l->n_dcon;
441			l->n_sp = NULL;
442			l->n_op = ICON;
443			l->n_type = m;
444			l->n_ap = NULL;
445			nfree(p);
446			return clocal(l);
447		}
448		if ((p->n_type == CHAR || p->n_type == UCHAR ||
449		    p->n_type == SHORT || p->n_type == USHORT) &&
450		    (l->n_type == FLOAT || l->n_type == DOUBLE ||
451		    l->n_type == LDOUBLE)) {
452			p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap);
453			p->n_left->n_type = INT;
454			return p;
455		}
456		break;
457
458	case MOD:
459	case DIV:
460		if (o == DIV && p->n_type != CHAR && p->n_type != SHORT)
461			break;
462		if (o == MOD && p->n_type != CHAR && p->n_type != SHORT)
463			break;
464		/* make it an int division by inserting conversions */
465		p->n_left = makety(p->n_left, INT, 0, 0, 0);
466		p->n_right = makety(p->n_right, INT, 0, 0, 0);
467		p = makety(p, p->n_type, 0, 0, 0);
468		p->n_left->n_type = INT;
469		break;
470
471	case FORCE:
472		/* put return value in return reg */
473		p->n_op = ASSIGN;
474		p->n_right = p->n_left;
475		p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0);
476		t = p->n_type;
477		if (ISITY(t))
478			t = t - (FIMAG-FLOAT);
479		p->n_left->n_rval = p->n_left->n_type == BOOL ?
480		    RETREG(CHAR) : RETREG(t);
481		break;
482
483	case LS:
484	case RS:
485		/* shift count must be in a char */
486		if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR)
487			break;
488		p->n_right = makety(p->n_right, CHAR, 0, 0, 0);
489		break;
490	}
491#ifdef PCC_DEBUG
492	if (xdebug) {
493		printf("clocal end: %p\n", p);
494		fwalk(p, eprint, 0);
495	}
496#endif
497	return(p);
498}
499
500void
501myp2tree(NODE *p)
502{
503	struct symtab *sp, sps;
504	static int dblxor, fltxor;
505
506	if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) {
507		/* Store xor code for sign change */
508		if (dblxor == 0) {
509			dblxor = getlab();
510			fltxor = getlab();
511			sps.stype = LDOUBLE;
512			sps.squal = CON >> TSHIFT;
513			sps.sflags = sps.sclass = 0;
514			sps.sname = sps.soname = "";
515			sps.slevel = 1;
516			sps.sap = NULL;
517			sps.soffset = dblxor;
518			locctr(DATA, &sps);
519			defloc(&sps);
520			printf("\t.long 0,0x80000000,0,0\n");
521			printf(LABFMT ":\n", fltxor);
522			printf("\t.long 0x80000000,0,0,0\n");
523		}
524		p->n_label = p->n_type == FLOAT ? fltxor : dblxor;
525		return;
526	}
527	if (kflag && (cdope(p->n_op) & CALLFLG) && p->n_left->n_op == NAME) {
528		/* Convert @GOTPCREL to @PLT */
529		char *s;
530
531		sp = p->n_left->n_sp;
532		if ((s = strstr(sp->sname, "@GOTPCREL")) != NULL) {
533			strcpy(s, "@PLT");
534			p->n_left->n_op = ICON;
535		}
536		return;
537	}
538	if (p->n_op != FCON)
539		return;
540
541#ifdef mach_amd64
542	{
543		/* Do not loose negative zeros */
544		long long *llp = (long long *)(&p->n_dcon);
545		short *ssp = (short *)&llp[1];
546		if (*llp == 0 && *ssp == 0)
547			return;
548	}
549#else
550#error fixme
551#endif
552
553	/* XXX should let float constants follow */
554	sp = IALLOC(sizeof(struct symtab));
555	sp->sclass = STATIC;
556	sp->sap = NULL;
557	sp->slevel = 1; /* fake numeric label */
558	sp->soffset = getlab();
559	sp->sflags = 0;
560	sp->stype = p->n_type;
561	sp->squal = (CON >> TSHIFT);
562	sp->sname = sp->soname = NULL;
563
564	locctr(DATA, sp);
565	defloc(sp);
566	ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p);
567
568	p->n_op = NAME;
569	p->n_lval = 0;
570	p->n_sp = sp;
571}
572
573/*
574 * Convert ADDROF NAME to ICON?
575 */
576int
577andable(NODE *p)
578{
579	if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC)
580		return 1;
581	return !kflag;
582}
583
584/*
585 * Return 1 if a variable of type type is OK to put in register.
586 */
587int
588cisreg(TWORD t)
589{
590	if (t == LDOUBLE)
591		return 0;
592	return 1;
593}
594
595/*
596 * Allocate off bits on the stack.  p is a tree that when evaluated
597 * is the multiply count for off, t is a storeable node where to write
598 * the allocated address.
599 */
600void
601spalloc(NODE *t, NODE *p, OFFSZ off)
602{
603	NODE *sp;
604
605	p = buildtree(MUL, p, bcon(off/SZCHAR));
606	p = buildtree(PLUS, p, bcon(30));
607	p = buildtree(AND, p, xbcon(-16, NULL, LONG));
608
609	/* sub the size from sp */
610	sp = block(REG, NIL, NIL, p->n_type, 0, 0);
611	sp->n_lval = 0;
612	sp->n_rval = STKREG;
613	ecomp(buildtree(MINUSEQ, sp, p));
614
615	/* save the address of sp */
616	sp = block(REG, NIL, NIL, PTR+LONG, t->n_df, t->n_ap);
617	sp->n_lval = 0;
618	sp->n_rval = STKREG;
619	t->n_type = sp->n_type;
620	ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */
621
622}
623
624/*
625 * print out a constant node, may be associated with a label.
626 * Do not free the node after use.
627 * off is bit offset from the beginning of the aggregate
628 * fsz is the number of bits this is referring to
629 */
630int
631ninval(CONSZ off, int fsz, NODE *p)
632{
633	union { float f; double d; long double l; int i[3]; } u;
634
635	switch (p->n_type) {
636	case LDOUBLE:
637		u.i[2] = 0;
638		u.l = (long double)p->n_dcon;
639#if defined(HOST_BIG_ENDIAN)
640		/* XXX probably broken on most hosts */
641		printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[2], u.i[1], u.i[0]);
642#else
643		printf("\t.long\t0x%x,0x%x,0x%x,0\n", u.i[0], u.i[1], u.i[2]);
644#endif
645		break;
646	case DOUBLE:
647		u.d = (double)p->n_dcon;
648#if defined(HOST_BIG_ENDIAN)
649		printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]);
650#else
651		printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]);
652#endif
653		break;
654	case FLOAT:
655		u.f = (float)p->n_dcon;
656		printf("\t.long\t0x%x\n", u.i[0]);
657		break;
658	default:
659		return 0;
660	}
661	return 1;
662}
663
664/* make a name look like an external name in the local machine */
665char *
666exname(char *p)
667{
668#ifdef MACHOABI
669
670#define NCHNAM	256
671	static char text[NCHNAM+1];
672	int i;
673
674	if (p == NULL)
675		return "";
676
677	text[0] = '_';
678	for (i=1; *p && i<NCHNAM; ++i)
679		text[i] = *p++;
680
681	text[i] = '\0';
682	text[NCHNAM] = '\0';  /* truncate */
683
684	return (text);
685#else
686	return (p == NULL ? "" : p);
687#endif
688}
689
690/*
691 * map types which are not defined on the local machine
692 */
693TWORD
694ctype(TWORD type)
695{
696	switch (BTYPE(type)) {
697	case LONGLONG:
698		MODTYPE(type,LONG);
699		break;
700
701	case ULONGLONG:
702		MODTYPE(type,ULONG);
703
704	}
705	return (type);
706}
707
708void
709calldec(NODE *p, NODE *q)
710{
711}
712
713void
714extdec(struct symtab *q)
715{
716}
717
718/* make a common declaration for id, if reasonable */
719void
720defzero(struct symtab *sp)
721{
722	int off, al;
723	char *name;
724
725	if ((name = sp->soname) == NULL)
726		name = exname(sp->sname);
727	off = tsize(sp->stype, sp->sdf, sp->sap);
728	SETOFF(off,SZCHAR);
729	off /= SZCHAR;
730	al = talign(sp->stype, sp->sap)/SZCHAR;
731
732	if (sp->sclass == STATIC) {
733		if (sp->slevel == 0) {
734			printf("\t.local %s\n", name);
735		} else
736			printf("\t.local " LABFMT "\n", sp->soffset);
737	}
738	if (sp->slevel == 0) {
739		printf("\t.comm %s,0%o,%d\n", name, off, al);
740	} else
741		printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al);
742}
743
744static char *
745section2string(char *name, int len)
746{
747	char *s;
748	int n;
749
750	if (strncmp(name, "link_set", 8) == 0) {
751		const char *postfix = ",\"aw\",@progbits";
752		n = len + strlen(postfix) + 1;
753		s = IALLOC(n);
754		strlcpy(s, name, n);
755		strlcat(s, postfix, n);
756		return s;
757	}
758
759	return newstring(name, len);
760}
761
762char *nextsect;
763static int gottls;
764static char *alias;
765static int constructor;
766static int destructor;
767
768/*
769 * Give target the opportunity of handling pragmas.
770 */
771int
772mypragma(char *str)
773{
774	char *a2 = pragtok(NULL);
775
776	if (strcmp(str, "tls") == 0 && a2 == NULL) {
777		gottls = 1;
778		return 1;
779	}
780	if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) {
781		constructor = 1;
782		return 1;
783	}
784	if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) {
785		destructor = 1;
786		return 1;
787	}
788	if (strcmp(str, "section") == 0 && a2 != NULL) {
789		nextsect = section2string(a2, strlen(a2));
790		return 1;
791	}
792	if (strcmp(str, "alias") == 0 && a2 != NULL) {
793		alias = tmpstrdup(a2);
794		return 1;
795	}
796
797	return 0;
798}
799
800/*
801 * Called when a identifier has been declared.
802 */
803void
804fixdef(struct symtab *sp)
805{
806	struct attr *ga;
807
808	/* may have sanity checks here */
809	if (gottls)
810		sp->sflags |= STLS;
811	gottls = 0;
812
813#ifdef HAVE_WEAKREF
814	/* not many as'es have this directive */
815	if ((ga = gcc_get_attr(sp->sap, GCC_ATYP_WEAKREF)) != NULL) {
816		char *wr = ga->a1.sarg;
817		char *sn = sp->soname ? sp->soname : sp->sname;
818		if (wr == NULL) {
819			if ((ga = gcc_get_attr(sp->sap, GCC_ATYP_ALIAS))) {
820				wr = ga->a1.sarg;
821			}
822		}
823		if (wr == NULL)
824			printf("\t.weak %s\n", sn);
825		else
826			printf("\t.weakref %s,%s\n", sn, wr);
827	} else
828#endif
829	       if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) {
830		char *an = ga->sarg(0);
831		char *sn = sp->soname ? sp->soname : sp->sname;
832		char *v;
833
834		v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl";
835		printf("\t.%s %s\n", v, sn);
836		printf("\t.set %s,%s\n", sn, an);
837	}
838	if (alias != NULL && (sp->sclass != PARAM)) {
839		printf("\t.globl %s\n", exname(sp->soname));
840		printf("%s = ", exname(sp->soname));
841		printf("%s\n", exname(alias));
842		alias = NULL;
843	}
844	if ((constructor || destructor) && (sp->sclass != PARAM)) {
845		NODE *p = talloc();
846
847		p->n_op = NAME;
848		p->n_sp =
849		  (struct symtab *)(constructor ? "constructor" : "destructor");
850		sp->sap = attr_add(sp->sap, gcc_attr_parse(p));
851		constructor = destructor = 0;
852	}
853}
854
855NODE *
856i386_builtin_return_address(NODE *f, NODE *a, TWORD t)
857{
858	int nframes;
859
860	if (a == NULL || a->n_op != ICON)
861		goto bad;
862
863	nframes = a->n_lval;
864
865	tfree(f);
866	tfree(a);
867
868	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
869	regno(f) = FPREG;
870
871	while (nframes--)
872		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
873
874	f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, 0);
875	f = buildtree(UMUL, f, NIL);
876
877	return f;
878bad:
879        uerror("bad argument to __builtin_return_address");
880        return bcon(0);
881}
882
883NODE *
884i386_builtin_frame_address(NODE *f, NODE *a, TWORD t)
885{
886	int nframes;
887
888	if (a == NULL || a->n_op != ICON)
889		goto bad;
890
891	nframes = a->n_lval;
892
893	tfree(f);
894	tfree(a);
895
896	f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
897	regno(f) = FPREG;
898
899	while (nframes--)
900		f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
901
902	return f;
903bad:
904        uerror("bad argument to __builtin_frame_address");
905        return bcon(0);
906}
907
908void
909pass1_lastchance(struct interpass *ip)
910{
911}
912