1 /* $Id: code.c,v 1.85 2014/09/15 14:06:26 ragge Exp $ */
2 /*
3 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
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 /*
33 * Print out assembler segment name.
34 */
35 void
setseg(int seg,char * name)36 setseg(int seg, char *name)
37 {
38 switch (seg) {
39 case PROG: name = ".text"; break;
40 case DATA:
41 case LDATA: name = ".data"; break;
42 case UDATA: break;
43 #ifdef MACHOABI
44 case PICLDATA:
45 case PICDATA: name = ".section .data.rel.rw,\"aw\""; break;
46 case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break;
47 case STRNG: name = ".cstring"; break;
48 case RDATA: name = ".const_data"; break;
49 #else
50 case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break;
51 case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break;
52 case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break;
53 case STRNG:
54 #ifdef AOUTABI
55 case RDATA: name = ".data"; break;
56 #else
57 case RDATA: name = ".section .rodata"; break;
58 #endif
59 #endif
60 case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break;
61 case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break;
62 #ifdef MACHOABI
63 case CTORS: name = ".mod_init_func\n\t.align 2"; break;
64 case DTORS: name = ".mod_term_func\n\t.align 2"; break;
65 #else
66 case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break;
67 case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break;
68 #endif
69 case NMSEG:
70 printf("\t.section %s,\"a%c\",@progbits\n", name,
71 cftnsp ? 'x' : 'w');
72 return;
73 }
74 printf("\t%s\n", name);
75 }
76
77 #ifdef MACHOABI
78 void
defalign(int al)79 defalign(int al)
80 {
81 printf("\t.align %d\n", ispow2(al/ALCHAR));
82 }
83 #endif
84
85 /*
86 * Define everything needed to print out some data (or text).
87 * This means segment, alignment, visibility, etc.
88 */
89 void
defloc(struct symtab * sp)90 defloc(struct symtab *sp)
91 {
92 char *name;
93
94 if ((name = sp->soname) == NULL)
95 name = exname(sp->sname);
96 if (sp->sclass == EXTDEF) {
97 printf(" .globl %s\n", name);
98 #if defined(ELFABI)
99 printf("\t.type %s,@%s\n", name,
100 ISFTN(sp->stype)? "function" : "object");
101 #endif
102 }
103 #if defined(ELFABI)
104 if (!ISFTN(sp->stype)) {
105 if (sp->slevel == 0)
106 printf("\t.size %s,%d\n", name,
107 (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
108 else
109 printf("\t.size " LABFMT ",%d\n", sp->soffset,
110 (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR);
111 }
112 #endif
113 if (sp->slevel == 0)
114 printf("%s:\n", name);
115 else
116 printf(LABFMT ":\n", sp->soffset);
117 }
118
119 int structrettemp;
120
121 /*
122 * code for the end of a function
123 * deals with struct return here
124 */
125 void
efcode(void)126 efcode(void)
127 {
128 extern int gotnr;
129 NODE *p, *q;
130
131 gotnr = 0; /* new number for next fun */
132 if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN)
133 return;
134
135 /* struct return for small structs */
136 int sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
137 #if defined(os_openbsd)
138 if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) {
139 #else
140 if (sz == SZLONGLONG && attr_find(cftnsp->sap, ATTR_COMPLEX)) {
141 #endif
142 /* Pointer to struct in eax */
143 if (sz == SZLONGLONG) {
144 q = block(OREG, NIL, NIL, INT, 0, 0);
145 q->n_lval = 4;
146 p = block(REG, NIL, NIL, INT, 0, 0);
147 p->n_rval = EDX;
148 ecomp(buildtree(ASSIGN, p, q));
149 }
150 if (sz < SZSHORT) sz = CHAR;
151 else if (sz > SZSHORT) sz = INT;
152 else sz = SHORT;
153 q = block(OREG, NIL, NIL, sz, 0, 0);
154 p = block(REG, NIL, NIL, sz, 0, 0);
155 ecomp(buildtree(ASSIGN, p, q));
156 return;
157 }
158
159 /* Create struct assignment */
160 q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap);
161 q = buildtree(UMUL, q, NIL);
162 p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap);
163 p = buildtree(UMUL, p, NIL);
164 p = buildtree(ASSIGN, q, p);
165 ecomp(p);
166
167 /* put hidden arg in eax on return */
168 q = tempnode(structrettemp, INT, 0, 0);
169 p = block(REG, NIL, NIL, INT, 0, 0);
170 regno(p) = EAX;
171 ecomp(buildtree(ASSIGN, p, q));
172 }
173
174 static TWORD longregs[] = { EAXEDX, EDXECX };
175 static TWORD regpregs[] = { EAX, EDX, ECX };
176 static TWORD charregs[] = { AL, DL, CL };
177
178 /*
179 * code for the beginning of a function; a is an array of
180 * indices in symtab for the arguments; n is the number
181 *
182 * Classifying args on i386; not simple:
183 * - Args may be on stack or in registers (regparm)
184 * - There may be a hidden first arg, unless OpenBSD struct return.
185 * - Regparm syntax is not well documented.
186 * - There may be stdcall functions, where the called function pops stack
187 * - ...probably more
188 */
189 void
190 bfcode(struct symtab **sp, int cnt)
191 {
192 extern int argstacksize;
193 #ifdef GCC_COMPAT
194 struct attr *ap;
195 #endif
196 struct symtab *sp2;
197 extern int gotnr;
198 NODE *n, *p;
199 int i, regparmarg;
200 int argbase, nrarg, sz;
201
202 /* Take care of PIC stuff first */
203 if (kflag) {
204 #define STL 200
205 char *str = inlalloc(STL);
206 #if !defined(MACHOABI)
207 int l = getlab();
208 #else
209 char *name;
210 #endif
211
212 /* Generate extended assembler for PIC prolog */
213 p = tempnode(0, INT, 0, 0);
214 gotnr = regno(p);
215 p = block(XARG, p, NIL, INT, 0, 0);
216 p->n_name = "=g";
217 p = block(XASM, p, bcon(0), INT, 0, 0);
218
219 #if defined(MACHOABI)
220 if ((name = cftnsp->soname) == NULL)
221 name = cftnsp->sname;
222 if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n",
223 name, name) >= STL)
224 cerror("bfcode");
225 #else
226 if (snprintf(str, STL,
227 "call " LABFMT "\n" LABFMT ":\n\tpopl %%0\n"
228 "\taddl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0\n",
229 l, l, l) >= STL)
230 cerror("bfcode");
231 #endif
232 p->n_name = str;
233 p->n_right->n_type = STRTY;
234 ecomp(p);
235 }
236
237 argbase = ARGINIT;
238 nrarg = regparmarg = 0;
239 argstacksize = 0;
240
241 #ifdef GCC_COMPAT
242 if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL)
243 cftnsp->sflags |= SSTDCALL;
244 if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM)))
245 regparmarg = ap->iarg(0);
246 #endif
247
248 /* Function returns struct, create return arg node */
249 if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) {
250 sz = tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap);
251 #if defined(os_openbsd)
252 /* OpenBSD uses non-standard return for small structs */
253 if (sz > SZLONGLONG)
254 #else
255 if (sz != SZLONGLONG ||
256 attr_find(cftnsp->sap, ATTR_COMPLEX) == 0)
257 #endif
258 {
259 if (regparmarg) {
260 n = block(REG, 0, 0, INT, 0, 0);
261 regno(n) = regpregs[nrarg++];
262 } else {
263 n = block(OREG, 0, 0, INT, 0, 0);
264 n->n_lval = argbase/SZCHAR;
265 argbase += SZINT;
266 regno(n) = FPREG;
267 argstacksize += 4; /* popped by callee */
268 }
269 p = tempnode(0, INT, 0, 0);
270 structrettemp = regno(p);
271 p = buildtree(ASSIGN, p, n);
272 ecomp(p);
273 }
274 }
275
276 /*
277 * Find where all params are so that they end up at the right place.
278 * At the same time recalculate their arg offset on stack.
279 * We also get the "pop size" for stdcall.
280 */
281 for (i = 0; i < cnt; i++) {
282 sp2 = sp[i];
283 sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
284
285 SETOFF(sz, SZINT);
286
287 if (cisreg(sp2->stype) == 0 ||
288 ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */
289 sp2->soffset = argbase;
290 argbase += sz;
291 nrarg = regparmarg; /* no more in reg either */
292 } else { /* in reg */
293 sp2->soffset = nrarg;
294 nrarg += sz/SZINT;
295 sp2->sclass = REGISTER;
296 }
297 }
298
299 /*
300 * Now (argbase - ARGINIT) is used space on stack.
301 * Move (if necessary) the args to something new.
302 */
303 for (i = 0; i < cnt; i++) {
304 int reg, j;
305
306 sp2 = sp[i];
307
308 if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) {
309 /* must move to stack */
310 sz = tsize(sp2->stype, sp2->sdf, sp2->sap);
311 SETOFF(sz, SZINT);
312 SETOFF(autooff, SZINT);
313 reg = sp2->soffset;
314 sp2->sclass = AUTO;
315 sp2->soffset = NOOFFSET;
316 oalloc(sp2, &autooff);
317 for (j = 0; j < sz/SZCHAR; j += 4) {
318 p = block(OREG, 0, 0, INT, 0, 0);
319 p->n_lval = sp2->soffset/SZCHAR + j;
320 regno(p) = FPREG;
321 n = block(REG, 0, 0, INT, 0, 0);
322 regno(n) = regpregs[reg++];
323 p = block(ASSIGN, p, n, INT, 0, 0);
324 ecomp(p);
325 }
326 } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) &&
327 ((cqual(sp2->stype, sp2->squal) & VOL) == 0) && xtemps) {
328 /* just put rest in temps */
329 if (sp2->sclass == REGISTER) {
330 n = block(REG, 0, 0, sp2->stype,
331 sp2->sdf, sp2->sap);
332 if (ISLONGLONG(sp2->stype))
333 regno(n) = longregs[sp2->soffset];
334 else if (DEUNSIGN(sp2->stype) == CHAR ||
335 sp2->stype == BOOL)
336 regno(n) = charregs[sp2->soffset];
337 else
338 regno(n) = regpregs[sp2->soffset];
339 } else {
340 n = block(OREG, 0, 0, sp2->stype,
341 sp2->sdf, sp2->sap);
342 n->n_lval = sp2->soffset/SZCHAR;
343 regno(n) = FPREG;
344 }
345 p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap);
346 sp2->soffset = regno(p);
347 sp2->sflags |= STNODE;
348 n = buildtree(ASSIGN, p, n);
349 ecomp(n);
350 }
351 }
352
353 if (cftnsp->sflags & SSTDCALL) {
354 /* XXX interaction STDCALL and struct return? */
355 argstacksize += (argbase - ARGINIT)/SZCHAR;
356 #ifdef os_win32
357
358 char buf[256];
359 char *name;
360 /*
361 * mangle name in symbol table as a callee.
362 */
363 if ((name = cftnsp->soname) == NULL)
364 name = exname(cftnsp->sname);
365 snprintf(buf, 256, "%s@%d", name, argstacksize);
366 cftnsp->soname = addname(buf);
367 #endif
368 }
369
370 }
371
372 #if defined(MACHOABI)
373 struct stub stublist;
374 struct stub nlplist;
375 #endif
376
377 /* called just before final exit */
378 /* flag is 1 if errors, 0 if none */
379 void
380 ejobcode(int flag)
381 {
382 #if defined(MACHOABI)
383 /*
384 * iterate over the stublist and output the PIC stubs
385 ` */
386 if (kflag) {
387 struct stub *p;
388
389 DLIST_FOREACH(p, &stublist, link) {
390 printf("\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n");
391 printf("L%s$stub:\n", p->name);
392 printf("\t.indirect_symbol %s\n", p->name);
393 printf("\thlt ; hlt ; hlt ; hlt ; hlt\n");
394 printf("\t.subsections_via_symbols\n");
395 }
396
397 printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n");
398 DLIST_FOREACH(p, &nlplist, link) {
399 printf("L%s$non_lazy_ptr:\n", p->name);
400 printf("\t.indirect_symbol %s\n", p->name);
401 printf("\t.long 0\n");
402 }
403
404 }
405 #endif
406
407 printf("\t.ident \"PCC: %s\"\n", VERSSTR);
408 }
409
410 void
411 bjobcode(void)
412 {
413 #ifdef os_sunos
414 astypnames[SHORT] = astypnames[USHORT] = "\t.2byte";
415 #endif
416 astypnames[INT] = astypnames[UNSIGNED] = "\t.long";
417 #if defined(MACHOABI)
418 DLIST_INIT(&stublist, link);
419 DLIST_INIT(&nlplist, link);
420 #endif
421 #if defined(__GNUC__) || defined(__PCC__)
422 /* Be sure that the compiler uses full x87 */
423 /* XXX cross-compiling will fail here */
424 int fcw;
425 __asm("fstcw (%0)" : : "r"(&fcw));
426 fcw |= 0x300;
427 __asm("fldcw (%0)" : : "r"(&fcw));
428 #endif
429 }
430
431 /*
432 * Convert FUNARG to assign in case of regparm.
433 */
434 static int regcvt, rparg;
435 static void
436 addreg(NODE *p)
437 {
438 TWORD t;
439 NODE *q;
440 int sz, r;
441
442 sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR;
443 sz = (sz + 3) >> 2; /* sz in regs */
444 if ((regcvt+sz) > rparg) {
445 regcvt = rparg;
446 return;
447 }
448 if (sz > 2)
449 uerror("cannot put struct in 3 regs (yet)");
450
451 if (sz == 2)
452 r = regcvt == 0 ? EAXEDX : EDXECX;
453 else
454 r = regcvt == 0 ? EAX : regcvt == 1 ? EDX : ECX;
455
456 if (p->n_op == FUNARG) {
457 /* at most 2 regs */
458 if (p->n_type < INT) {
459 p->n_left = ccast(p->n_left, INT, 0, 0, 0);
460 p->n_type = INT;
461 }
462
463 p->n_op = ASSIGN;
464 p->n_right = p->n_left;
465 } else if (p->n_op == STARG) {
466 /* convert to ptr, put in reg */
467 q = p->n_left;
468 t = sz == 2 ? LONGLONG : INT;
469 q = cast(q, INCREF(t), 0);
470 q = buildtree(UMUL, q, NIL);
471 p->n_op = ASSIGN;
472 p->n_type = t;
473 p->n_right = q;
474 } else
475 cerror("addreg");
476 p->n_left = block(REG, 0, 0, p->n_type, 0, 0);
477 regno(p->n_left) = r;
478 regcvt += sz;
479 }
480
481 /*
482 * Called with a function call with arguments as argument.
483 * This is done early in buildtree() and only done once.
484 * Returns p.
485 */
486 NODE *
487 funcode(NODE *p)
488 {
489 extern int gotnr;
490 #ifdef GCC_COMPAT
491 struct attr *ap;
492 #endif
493 NODE *r, *l;
494 TWORD t = DECREF(DECREF(p->n_left->n_type));
495 int stcall;
496
497 stcall = ISSOU(t);
498 /*
499 * We may have to prepend:
500 * - Hidden arg0 for struct return (in reg or on stack).
501 * - ebx in case of PIC code.
502 */
503
504 /* Fix function call arguments. On x86, just add funarg */
505 for (r = p->n_right; r->n_op == CM; r = r->n_left) {
506 if (r->n_right->n_op != STARG)
507 r->n_right = block(FUNARG, r->n_right, NIL,
508 r->n_right->n_type, r->n_right->n_df,
509 r->n_right->n_ap);
510 }
511 if (r->n_op != STARG) {
512 l = talloc();
513 *l = *r;
514 r->n_op = FUNARG;
515 r->n_left = l;
516 r->n_type = l->n_type;
517 }
518 #ifdef os_openbsd
519 if (stcall && (ap = strattr(p->n_left->n_ap)) &&
520 ap->amsize != SZCHAR && ap->amsize != SZSHORT &&
521 ap->amsize != SZINT && ap->amsize != SZLONGLONG)
522 #else
523 if (stcall &&
524 (attr_find(p->n_left->n_ap, ATTR_COMPLEX) == 0 ||
525 ((ap = strattr(p->n_left->n_ap)) && ap->amsize > SZLONGLONG)))
526 #endif
527 {
528 /* Prepend a placeholder for struct address. */
529 /* Use EBP, can never show up under normal circumstances */
530 l = talloc();
531 *l = *r;
532 r->n_op = CM;
533 r->n_right = l;
534 r->n_type = INT;
535 l = block(REG, 0, 0, INCREF(VOID), 0, 0);
536 regno(l) = EBP;
537 l = block(FUNARG, l, 0, INCREF(VOID), 0, 0);
538 r->n_left = l;
539 }
540
541 #ifdef GCC_COMPAT
542 if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM)))
543 rparg = ap->iarg(0);
544 else
545 #endif
546 rparg = 0;
547
548 regcvt = 0;
549 if (rparg)
550 listf(p->n_right, addreg);
551
552 if (kflag == 0)
553 return p;
554
555 #if defined(ELFABI)
556 /* Create an ASSIGN node for ebx */
557 l = block(REG, NIL, NIL, INT, 0, 0);
558 l->n_rval = EBX;
559 l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0));
560 if (p->n_right->n_op != CM) {
561 p->n_right = block(CM, l, p->n_right, INT, 0, 0);
562 } else {
563 for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left)
564 ;
565 r->n_left = block(CM, l, r->n_left, INT, 0, 0);
566 }
567 #endif
568 return p;
569 }
570
571 /* fix up type of field p */
572 void
573 fldty(struct symtab *p)
574 {
575 }
576
577 /*
578 * XXX - fix genswitch.
579 */
580 int
581 mygenswitch(int num, TWORD type, struct swents **p, int n)
582 {
583 return 0;
584 }
585
586 NODE *
587 builtin_return_address(const struct bitable *bt, NODE *a)
588 {
589 int nframes;
590 NODE *f;
591
592 if (a->n_op != ICON)
593 goto bad;
594
595 nframes = (int)a->n_lval;
596
597 tfree(a);
598
599 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
600 regno(f) = FPREG;
601
602 while (nframes--)
603 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
604
605 f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, 0);
606 f = buildtree(UMUL, f, NIL);
607
608 return f;
609 bad:
610 uerror("bad argument to __builtin_return_address");
611 return bcon(0);
612 }
613
614 NODE *
615 builtin_frame_address(const struct bitable *bt, NODE *a)
616 {
617 int nframes;
618 NODE *f;
619
620 if (a->n_op != ICON)
621 goto bad;
622
623 nframes = (int)a->n_lval;
624
625 tfree(a);
626
627 f = block(REG, NIL, NIL, PTR+VOID, 0, 0);
628 regno(f) = FPREG;
629
630 while (nframes--)
631 f = block(UMUL, f, NIL, PTR+VOID, 0, 0);
632
633 return f;
634 bad:
635 uerror("bad argument to __builtin_frame_address");
636 return bcon(0);
637 }
638
639 /*
640 * Return "canonical frame address".
641 */
642 NODE *
643 builtin_cfa(const struct bitable *bt, NODE *a)
644 {
645 uerror("missing builtin_cfa");
646 return bcon(0);
647 }
648
649