xref: /netbsd/external/bsd/pcc/dist/pcc/arch/i386/code.c (revision 6550d01e)
1 /*	Id: code.c,v 1.52 2010/04/28 14:53:54 ragge Exp 	*/
2 /*	$NetBSD: code.c,v 1.1.1.3 2010/06/03 18:57:14 plunky Exp $	*/
3 /*
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 # include "pass1.h"
32 
33 int lastloc = -1;
34 
35 /*
36  * Define everything needed to print out some data (or text).
37  * This means segment, alignment, visibility, etc.
38  */
39 void
40 defloc(struct symtab *sp)
41 {
42 	extern char *nextsect;
43 	int weak = 0;
44 	char *name = NULL;
45 #if defined(ELFABI) || defined(PECOFFABI)
46 	static char *loctbl[] = { "text", "data", "section .rodata" };
47 #elif defined(MACHOABI)
48 	static char *loctbl[] = { "text", "data", "const_data" };
49 #endif
50 	TWORD t;
51 	int s, al;
52 
53 	if (sp == NULL) {
54 		lastloc = -1;
55 		return;
56 	}
57 	t = sp->stype;
58 	s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA;
59 	if ((name = sp->soname) == NULL)
60 		name = exname(sp->sname);
61 #ifdef TLS
62 	if (sp->sflags & STLS) {
63 		if (s != DATA)
64 			cerror("non-data symbol in tls section");
65 		nextsect = ".tdata";
66 	}
67 #endif
68 #ifdef GCC_COMPAT
69 	{
70 		struct gcc_attrib *ga;
71 
72 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_SECTION)) != NULL)
73 			nextsect = ga->a1.sarg;
74 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_WEAK)) != NULL)
75 			weak = 1;
76 		if (gcc_get_attr(sp->ssue, GCC_ATYP_DESTRUCTOR)) {
77 			printf("\t.section\t.dtors,\"aw\",@progbits\n");
78 			printf("\t.align 4\n\t.long\t%s\n", name);
79 			lastloc = -1;
80 		}
81 		if (gcc_get_attr(sp->ssue, GCC_ATYP_CONSTRUCTOR)) {
82 			printf("\t.section\t.ctors,\"aw\",@progbits\n");
83 			printf("\t.align 4\n\t.long\t%s\n", name);
84 			lastloc = -1;
85 		}
86 		if ((ga = gcc_get_attr(sp->ssue, GCC_ATYP_VISIBILITY)) &&
87 		    strcmp(ga->a1.sarg, "default"))
88 			printf("\t.%s %s\n", ga->a1.sarg, name);
89 	}
90 #endif
91 	if (nextsect) {
92 		printf("	.section %s,\"wa\",@progbits\n", nextsect);
93 		nextsect = NULL;
94 		s = -1;
95 	} else if (s != lastloc)
96 		printf("	.%s\n", loctbl[s]);
97 	lastloc = s;
98 	while (ISARY(t))
99 		t = DECREF(t);
100 	al = ISFTN(t) ? ALINT : talign(t, sp->ssue);
101 	if (al > ALCHAR)
102 		printf("	.align %d\n", al/ALCHAR);
103 	if (weak)
104 		printf("	.weak %s\n", name);
105 	else if (sp->sclass == EXTDEF) {
106 		printf("	.globl %s\n", name);
107 #if defined(ELFABI)
108 		printf("\t.type %s,@%s\n", name,
109 		    ISFTN(t)? "function" : "object");
110 #endif
111 	}
112 	if (sp->slevel == 0)
113 		printf("%s:\n", name);
114 	else
115 		printf(LABFMT ":\n", sp->soffset);
116 }
117 
118 /*
119  * code for the end of a function
120  * deals with struct return here
121  */
122 void
123 efcode()
124 {
125 	extern int gotnr;
126 	NODE *p, *q;
127 
128 	gotnr = 0;	/* new number for next fun */
129 	if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
130 		return;
131 #if defined(os_openbsd)
132 	/* struct return for small structs */
133 	int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->ssue);
134 	if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) {
135 		/* Pointer to struct in eax */
136 		if (sz == SZLONGLONG) {
137 			q = block(OREG, NIL, NIL, INT, 0, MKSUE(INT));
138 			q->n_lval = 4;
139 			p = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
140 			p->n_rval = EDX;
141 			ecomp(buildtree(ASSIGN, p, q));
142 		}
143 		if (sz < SZSHORT) sz = CHAR;
144 		else if (sz > SZSHORT) sz = INT;
145 		else sz = SHORT;
146 		q = block(OREG, NIL, NIL, sz, 0, MKSUE(sz));
147 		p = block(REG, NIL, NIL, sz, 0, MKSUE(sz));
148 		ecomp(buildtree(ASSIGN, p, q));
149 		return;
150 	}
151 #endif
152 	/* Create struct assignment */
153 	q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
154 	q->n_rval = EBP;
155 	q->n_lval = 8; /* return buffer offset */
156 	q = buildtree(UMUL, q, NIL);
157 	p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->ssue);
158 	p = buildtree(UMUL, p, NIL);
159 	p = buildtree(ASSIGN, q, p);
160 	ecomp(p);
161 }
162 
163 /*
164  * code for the beginning of a function; a is an array of
165  * indices in symtab for the arguments; n is the number
166  */
167 void
168 bfcode(struct symtab **sp, int cnt)
169 {
170 	extern int argstacksize;
171 	struct symtab *sp2;
172 	extern int gotnr;
173 	NODE *n, *p;
174 	int i;
175 
176 	if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
177 		/* Function returns struct, adjust arg offset */
178 #if defined(os_openbsd)
179 		/* OpenBSD uses non-standard return for small structs */
180 		int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->ssue);
181 		if (sz != SZCHAR && sz != SZSHORT &&
182 		    sz != SZINT && sz != SZLONGLONG)
183 #endif
184 			for (i = 0; i < cnt; i++)
185 				sp[i]->soffset += SZPOINT(INT);
186 	}
187 
188 #ifdef GCC_COMPAT
189 	if (gcc_get_attr(cftnsp->ssue, GCC_ATYP_STDCALL) != NULL)
190 		cftnsp->sflags |= SSTDCALL;
191 #endif
192 
193 	/*
194 	 * Count the arguments
195 	 */
196 	argstacksize = 0;
197 	if (cftnsp->sflags & SSTDCALL) {
198 #ifdef os_win32
199 
200 		char buf[256];
201 		char *name;
202 #endif
203 
204 		for (i = 0; i < cnt; i++) {
205 			TWORD t = sp[i]->stype;
206 			if (t == STRTY || t == UNIONTY)
207 				argstacksize +=
208 				    tsize(t, sp[i]->sdf, sp[i]->ssue);
209 			else
210 				argstacksize += szty(t) * SZINT / SZCHAR;
211 		}
212 #ifdef os_win32
213 		/*
214 		 * mangle name in symbol table as a callee.
215 		 */
216 		if ((name = cftnsp->soname) == NULL)
217 			name = exname(cftnsp->sname);
218 		snprintf(buf, 256, "%s@%d", name, argstacksize);
219 		cftnsp->soname = addname(buf);
220 #endif
221 	}
222 
223 	if (kflag) {
224 #define	STL	200
225 		char *str = inlalloc(STL);
226 #if !defined(MACHOABI)
227 		int l = getlab();
228 #else
229 		char *name;
230 #endif
231 
232 		/* Generate extended assembler for PIC prolog */
233 		p = tempnode(0, INT, 0, MKSUE(INT));
234 		gotnr = regno(p);
235 		p = block(XARG, p, NIL, INT, 0, MKSUE(INT));
236 		p->n_name = "=g";
237 		p = block(XASM, p, bcon(0), INT, 0, MKSUE(INT));
238 
239 #if defined(MACHOABI)
240 		if ((name = cftnsp->soname) == NULL)
241 			name = cftnsp->sname;
242 		if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
243 		    name, name) >= STL)
244 			cerror("bfcode");
245 #else
246 		if (snprintf(str, STL,
247 		    "call " LABFMT "\n" LABFMT ":\n	popl %%0\n"
248 		    "	addl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0\n",
249 		    l, l, l) >= STL)
250 			cerror("bfcode");
251 #endif
252 		p->n_name = str;
253 		p->n_right->n_type = STRTY;
254 		ecomp(p);
255 	}
256 	if (xtemps == 0)
257 		return;
258 
259 	/* put arguments in temporaries */
260 	for (i = 0; i < cnt; i++) {
261 		if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY ||
262 		    cisreg(sp[i]->stype) == 0)
263 			continue;
264 		if (cqual(sp[i]->stype, sp[i]->squal) & VOL)
265 			continue;
266 		sp2 = sp[i];
267 		n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->ssue);
268 		n = buildtree(ASSIGN, n, nametree(sp2));
269 		sp[i]->soffset = regno(n->n_left);
270 		sp[i]->sflags |= STNODE;
271 		ecomp(n);
272 	}
273 }
274 
275 
276 /*
277  * by now, the automatics and register variables are allocated
278  */
279 void
280 bccode()
281 {
282 	SETOFF(autooff, SZINT);
283 }
284 
285 #if defined(MACHOABI)
286 struct stub stublist;
287 struct stub nlplist;
288 #endif
289 
290 /* called just before final exit */
291 /* flag is 1 if errors, 0 if none */
292 void
293 ejobcode(int flag )
294 {
295 #if defined(MACHOABI)
296 	/*
297 	 * iterate over the stublist and output the PIC stubs
298 `	 */
299 	if (kflag) {
300 		struct stub *p;
301 
302 		DLIST_FOREACH(p, &stublist, link) {
303 			printf("\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n");
304 			printf("L%s$stub:\n", p->name);
305 			printf("\t.indirect_symbol %s\n", p->name);
306 			printf("\thlt ; hlt ; hlt ; hlt ; hlt\n");
307 			printf("\t.subsections_via_symbols\n");
308 		}
309 
310 		printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
311 		DLIST_FOREACH(p, &nlplist, link) {
312 			printf("L%s$non_lazy_ptr:\n", p->name);
313 			printf("\t.indirect_symbol %s\n", p->name);
314 			printf("\t.long 0\n");
315 	        }
316 
317 	}
318 #endif
319 
320 #define _MKSTR(x) #x
321 #define MKSTR(x) _MKSTR(x)
322 #define OS MKSTR(TARGOS)
323         printf("\t.ident \"PCC: %s (%s)\"\n", PACKAGE_STRING, OS);
324 }
325 
326 void
327 bjobcode()
328 {
329 #if defined(MACHOABI)
330 	DLIST_INIT(&stublist, link);
331 	DLIST_INIT(&nlplist, link);
332 #endif
333 }
334 
335 /*
336  * Called with a function call with arguments as argument.
337  * This is done early in buildtree() and only done once.
338  * Returns p.
339  */
340 NODE *
341 funcode(NODE *p)
342 {
343 	extern int gotnr;
344 	NODE *r, *l;
345 
346 	/* Fix function call arguments. On x86, just add funarg */
347 	for (r = p->n_right; r->n_op == CM; r = r->n_left) {
348 		if (r->n_right->n_op != STARG)
349 			r->n_right = block(FUNARG, r->n_right, NIL,
350 			    r->n_right->n_type, r->n_right->n_df,
351 			    r->n_right->n_sue);
352 	}
353 	if (r->n_op != STARG) {
354 		l = talloc();
355 		*l = *r;
356 		r->n_op = FUNARG;
357 		r->n_left = l;
358 		r->n_type = l->n_type;
359 	}
360 	if (kflag == 0)
361 		return p;
362 #if defined(ELFABI)
363 	/* Create an ASSIGN node for ebx */
364 	l = block(REG, NIL, NIL, INT, 0, MKSUE(INT));
365 	l->n_rval = EBX;
366 	l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, MKSUE(INT)));
367 	if (p->n_right->n_op != CM) {
368 		p->n_right = block(CM, l, p->n_right, INT, 0, MKSUE(INT));
369 	} else {
370 		for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
371 			;
372 		r->n_left = block(CM, l, r->n_left, INT, 0, MKSUE(INT));
373 	}
374 #endif
375 	return p;
376 }
377 
378 /*
379  * return the alignment of field of type t
380  */
381 int
382 fldal(unsigned int t)
383 {
384 	uerror("illegal field type");
385 	return(ALINT);
386 }
387 
388 /* fix up type of field p */
389 void
390 fldty(struct symtab *p)
391 {
392 }
393 
394 /*
395  * XXX - fix genswitch.
396  */
397 int
398 mygenswitch(int num, TWORD type, struct swents **p, int n)
399 {
400 	return 0;
401 }
402