/* * Create a reference for an extern variable. */ static NODE * picext(NODE *p) { NODE *q, *r; struct symtab *sp; char *name; q = tempnode(gotnr, PTR|VOID, 0, 0); name = getexname(p->n_sp); #ifdef notdef struct attr *ga; if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ga->sarg(0), "hidden") == 0) { /* For hidden vars use GOTOFF */ sp = picsymtab("", name, "@GOTOFF"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; } #endif sp = picsymtab("", name, "@GOT"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; }
static P1ND * tlsnonpic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; int ext = p->n_sp->sclass; char *name; name = getsoname(p->n_sp); sp = picsymtab("", name, ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF"); q = xbcon(0, sp, INT); if (ext == EXTERN) q = block(UMUL, q, NIL, PTR|VOID, 0, 0); sp2 = lookup("%gs:0", 0); sp2->stype = EXTERN|INT; r = nametree(sp2); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; }
/* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(30)); p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED)); p = cast(p, UNSIGNED, 0); /* sub the size from sp */ sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0); slval(sp, 0); sp->n_rval = STKREG; p = (buildtree(MINUSEQ, sp, p)); ecomp(p); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; p = (buildtree(ASSIGN, t, sp)); /* Emit! */ ecomp(p); }
static NODE * picstatic(NODE *p) { NODE *q, *r; struct symtab *sp; q = tempnode(gotnr, PTR|VOID, 0, 0); if (p->n_sp->slevel > 0) { char buf[32]; if ((p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf, "@GOT"); } else { sp = picsymtab("", getsoname(p->n_sp), "@GOT"); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; }
NODE * builtin_return_address(const struct bitable *bt, NODE *a) { NODE *f; int v; if (a->n_op != ICON) goto bad; v =a->n_lval; tfree(a); if (v != 0) { werror("unsupported argument"); return xbcon(0, NULL, VOID|PTR); } f = block(REG, NIL, NIL, INCREF(PTR+CHAR), 0, 0); regno(f) = FPREG; f = block(UMUL, block(PLUS, f, bcon(16), INCREF(PTR+CHAR), 0, 0), NIL, PTR+CHAR, 0, 0); f = makety(f, PTR+VOID, 0, 0, 0); return f; bad: uerror("bad argument to __builtin_return_address"); return bcon(0); }
/* * Get size of object, if possible. * Currently does nothing, */ static NODE * builtin_object_size(NODE *f, NODE *a, TWORD rt) { CONSZ v = icons(a->n_right); if (v < 0 || v > 3) uerror("arg2 must be between 0 and 3"); tfree(f); f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, rt)); nfree(a); return f; }
/* * Get size of object, if possible. * Currently does nothing, */ static NODE * builtin_object_size(const struct bitable *bt, NODE *a) { CONSZ v = icons(a->n_right); NODE *f; if (v < 0 || v > 3) uerror("arg2 must be between 0 and 3"); f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, bt->rt)); nfree(a); return f; }
static P1ND * import(P1ND *p) { struct attr *ap; P1ND *q; char *name; struct symtab *sp; name = getexname(p->n_sp); sp = picsymtab("__imp_", name, ""); q = xbcon(0, sp, PTR+VOID); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; }
/* * Sanitycheck "new" keyword. */ NODE * cxx_new(NODE *p) { NODE *q = p; NODE *t1 = bcon(1); int nw = NM_NEW; while (p->n_op == LB) { nw = NM_NWA; t1 = buildtree(MUL, t1, eve(p->n_right)); p->n_right = bcon(0); p = p->n_left; } if (p->n_op != TYPE) uerror("new used illegally"); t1 = buildtree(MUL, t1, xbcon(tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); tfree(q); return callftn(decoratename(NULL, nw), t1, NULL); }
/* * Create a reference for a TLS variable. */ static P1ND * tlspic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; char *name; /* * creates: * leal var@TLSGD(%ebx),%eax * call ___tls_get_addr@PLT */ /* calc address of var@TLSGD */ q = tempnode(gotnr, PTR|VOID, 0, 0); name = getsoname(p->n_sp); sp = picsymtab("", name, "@TLSGD"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); /* assign to %eax */ r = block(REG, NIL, NIL, PTR|VOID, 0, 0); r->n_rval = EAX; q = buildtree(ASSIGN, r, q); /* call ___tls_get_addr */ sp2 = lookup("___tls_get_addr@PLT", 0); sp2->stype = EXTERN|INT|FTN; r = nametree(sp2); r = buildtree(ADDROF, r, NIL); r = block(UCALL, r, NIL, INT, 0, 0); /* fusion both parts together */ q = buildtree(COMOP, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; }
/* * Create a reference for a static variable. */ static P1ND * picstatic(P1ND *p) { #if defined(ELFABI) P1ND *q, *r; struct symtab *sp; q = tempnode(gotnr, PTR|VOID, 0, 0); if (p->n_sp->slevel > 0) { char buf[32]; if ((p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf, "@GOTOFF"); } else sp = picsymtab("", getsoname(p->n_sp), "@GOTOFF"); sp->sclass = STATIC; sp->stype = p->n_sp->stype; r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #elif defined(MACHOABI) P1ND *q, *r; struct symtab *sp; char buf2[256]; snprintf(buf2, 256, "-L%s$pb", cftnsp->soname ? cftnsp->soname : cftnsp->sname); if (p->n_sp->slevel > 0) { char buf1[32]; snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf1, buf2); } else { char *name = getexname(p->n_sp); sp = picsymtab("", name, buf2); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; q = tempnode(gotnr, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; p1nfree(p); return q; #else /* defined(PECOFFABI) || defined(AOUTABI) */ return p; #endif }
/* * Create a reference for an extern variable. */ static P1ND * picext(P1ND *p) { struct attr *ap; #if defined(ELFABI) P1ND *q, *r; struct symtab *sp; char *name; q = tempnode(gotnr, PTR|VOID, 0, 0); name = getexname(p->n_sp); #ifdef GCC_COMPAT if ((ap = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ap->sarg(0), "hidden") == 0) { /* For hidden vars use GOTOFF */ sp = picsymtab("", name, "@GOTOFF"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } #endif sp = picsymtab("", name, "@GOT"); #ifdef GCC_COMPAT if (attr_find(p->n_sp->sap, GCC_ATYP_STDCALL) != NULL) p->n_sp->sflags |= SSTDCALL; #endif sp->sflags = p->n_sp->sflags & SSTDCALL; sp->sap = attr_add(p->n_sp->sap, sp->sap); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #elif defined(MACHOABI) P1ND *q, *r; struct symtab *sp; char buf2[256], *name, *pspn; name = getsoname(cftnsp); pspn = getexname(p->n_sp); if (p->n_sp->sclass == EXTDEF) { snprintf(buf2, 256, "-L%s$pb", name); sp = picsymtab("", pspn, buf2); } else { snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name); sp = picsymtab("L", pspn, buf2); addstub(&nlplist, pspn); } sp->stype = p->n_sp->stype; q = tempnode(gotnr, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); if (p->n_sp->sclass != EXTDEF) q = block(UMUL, q, 0, PTR+VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #else /* defined(PECOFFABI) || defined(AOUTABI) */ return p; #endif }