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