void patch(void) { vlong c, vexit; Prog *p, *q; Sym *s; int a; if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); mkfwd(); s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { a = p->as; if(a == ATEXT) curtext = p; if((a == AJAL || a == AJMP || a == ARET) && p->to.type != D_BRANCH && p->to.sym != S) { s = p->to.sym; if(s->type != STEXT) { diag("undefined: %s\n%P", s->name, p); s->type = STEXT; s->value = vexit; } p->to.offset = s->value; p->to.type = D_BRANCH; } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = firstp; q != P;) { if(q->forwd != P) if(c >= q->forwd->pc) { q = q->forwd; continue; } if(c == q->pc) break; q = q->link; } if(q == P) { diag("branch out of range %lld\n%P", c, p); p->to.type = D_NONE; } p->cond = q; } for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; if(p->cond != P) { p->cond = brloop(p->cond); if(p->cond != P) if(p->to.type == D_BRANCH) p->to.offset = p->cond->pc; } } }
void patch(void) { int32 c; Prog *p, *q; Sym *s; int32 vexit; Sym *plan9_tos; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); Bflush(&bso); mkfwd(); if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); s = lookup("exit", 0); vexit = s->value; plan9_tos = S; if(HEADTYPE == Hplan9x32) plan9_tos = lookup("_tos", 0); for(cursym = textp; cursym != nil; cursym = cursym->next) { for(p = cursym->text; p != P; p = p->link) { if(HEADTYPE == Hwindows) { // Convert // op n(GS), reg // to // MOVL 0x14(FS), reg // op n(reg), reg // The purpose of this patch is to fix some accesses // to extern register variables (TLS) on Windows, as // a different method is used to access them. if(p->from.type == D_INDIR+D_GS && p->to.type >= D_AX && p->to.type <= D_DI) { q = appendp(p); q->from = p->from; q->from.type = D_INDIR + p->to.type; q->to = p->to; q->as = p->as; p->as = AMOVL; p->from.type = D_INDIR+D_FS; p->from.offset = 0x14; } } if(HEADTYPE == Hlinux) { // Running binaries under Xen requires using // MOVL 0(GS), reg // and then off(reg) instead of saying off(GS) directly // when the offset is negative. if(p->from.type == D_INDIR+D_GS && p->from.offset < 0 && p->to.type >= D_AX && p->to.type <= D_DI) { q = appendp(p); q->from = p->from; q->from.type = D_INDIR + p->to.type; q->to = p->to; q->as = p->as; p->as = AMOVL; p->from.type = D_INDIR+D_GS; p->from.offset = 0; } } if(HEADTYPE == Hplan9x32) { if(p->from.type == D_INDIR+D_GS && p->to.type >= D_AX && p->to.type <= D_DI) { q = appendp(p); q->from = p->from; q->from.type = D_INDIR + p->to.type; q->to = p->to; q->as = p->as; p->as = AMOVL; p->from.type = D_EXTERN; p->from.sym = plan9_tos; p->from.offset = 0; } } if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH)) { s = p->to.sym; if(p->to.type == D_INDIR+D_ADDR) { /* skip check if this is an indirect call (CALL *symbol(SB)) */ continue; } else if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); if((s->type&~SSUB) != STEXT) { /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages } if(s->text == nil) continue; p->to.type = D_BRANCH; p->to.offset = s->text->pc; p->pcond = s->text; continue; } } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = cursym->text; q != P;) { if(c == q->pc) break; if(q->forwd != P && c >= q->forwd->pc) q = q->forwd; else q = q->link; } if(q == P) { diag("branch out of range in %s (%#ux)\n%P [%s]", TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); p->to.type = D_NONE; } p->pcond = q; } } for(cursym = textp; cursym != nil; cursym = cursym->next) { if(cursym->text == nil || cursym->p != nil) continue; for(p = cursym->text; p != P; p = p->link) { p->mark = 0; /* initialization for follow */ if(p->pcond != P) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) p->to.offset = p->pcond->pc; } } } }
void patch(void) { int32 c, vexit; Prog *p, *q; Sym *s, *s1; int a; if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); mkfwd(); s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { setarch(p); a = p->as; if(a == ATEXT) curtext = p; if(seenthumb && a == ABL){ // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S) // print("%s calls %s\n", s1->name, s->name); if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S && s->thumb != s1->thumb) s->foreign = 1; } if((a == ABL || a == ABX || a == AB || a == ARET) && p->to.type != D_BRANCH && p->to.sym != S) { s = p->to.sym; switch(s->type) { default: diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages case STEXT: p->to.offset = s->value; p->to.type = D_BRANCH; break; case SUNDEF: if(p->as != ABL) diag("help: SUNDEF in AB || ARET"); p->to.offset = 0; p->to.type = D_BRANCH; p->cond = UP; break; } } if(p->to.type != D_BRANCH || p->cond == UP) continue; c = p->to.offset; for(q = firstp; q != P;) { if(q->forwd != P) if(c >= q->forwd->pc) { q = q->forwd; continue; } if(c == q->pc) break; q = q->link; } if(q == P) { diag("branch out of range %ld\n%P", c, p); p->to.type = D_NONE; } p->cond = q; } for(p = firstp; p != P; p = p->link) { setarch(p); a = p->as; if(p->as == ATEXT) curtext = p; if(seenthumb && a == ABL) { #ifdef CALLEEBX if(0) {} #else if((s = p->to.sym) != S && (s->foreign || s->fnptr)) p->as = ABX; #endif else if(p->to.type == D_OREG) p->as = ABX; } if(p->cond != P && p->cond != UP) { p->cond = brloop(p->cond); if(p->cond != P) if(p->to.type == D_BRANCH) p->to.offset = p->cond->pc; } } }
void patch(void) { long c; Prog *p, *q; Sym *s; long vexit; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); Bflush(&bso); mkfwd(); if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); s = lookup("exit", 0); vexit = s->value; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; if(p->as == ACALL || p->as == ARET) { s = p->to.sym; if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); switch(s->type) { default: /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; break; /* or fall through to set offset? */ case STEXT: p->to.offset = s->value; break; case SUNDEF: p->pcond = UP; p->to.offset = 0; break; } p->to.type = D_BRANCH; } } if(p->to.type != D_BRANCH || p->pcond == UP) continue; c = p->to.offset; for(q = firstp; q != P;) { if(q->forwd != P) if(c >= q->forwd->pc) { q = q->forwd; continue; } if(c == q->pc) break; q = q->link; } if(q == P) { diag("branch out of range in %s\n%P", TNAME, p); p->to.type = D_NONE; } p->pcond = q; } for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) curtext = p; p->mark = 0; /* initialization for follow */ if(p->pcond != P && p->pcond != UP) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) p->to.offset = p->pcond->pc; } } }
void patch(void) { int32 c; Prog *p, *q; Sym *s; int32 vexit; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); Bflush(&bso); mkfwd(); if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); s = lookup("exit", 0); vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { if(HEADTYPE == Hwindows) { // Windows // Convert // op n(GS), reg // to // MOVL 0x28(GS), reg // op n(reg), reg // The purpose of this patch is to fix some accesses // to extern register variables (TLS) on Windows, as // a different method is used to access them. if(p->from.type == D_INDIR+D_GS && p->to.type >= D_AX && p->to.type <= D_DI && p->from.offset <= 8) { q = appendp(p); q->from = p->from; q->from.type = D_INDIR + p->to.type; q->to = p->to; q->as = p->as; p->as = AMOVQ; p->from.type = D_INDIR+D_GS; p->from.offset = 0x28; } } if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) { // ELF uses FS instead of GS. if(p->from.type == D_INDIR+D_GS) p->from.type = D_INDIR+D_FS; if(p->to.type == D_INDIR+D_GS) p->to.type = D_INDIR+D_FS; } if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { s = p->to.sym; if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); if((s->type&~SSUB) != STEXT) { /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages } if(s->text == nil) continue; p->to.type = D_BRANCH; p->to.offset = s->text->pc; p->pcond = s->text; continue; } } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = cursym->text; q != P;) { if(c == q->pc) break; if(q->forwd != P && c >= q->forwd->pc) q = q->forwd; else q = q->link; } if(q == P) { diag("branch out of range in %s (%#ux)\n%P [%s]", TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); p->to.type = D_NONE; } p->pcond = q; } for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { p->mark = 0; /* initialization for follow */ if(p->pcond != P) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) p->to.offset = p->pcond->pc; } } }
void patch(void) { int32 c, vexit; Prog *p, *q; Sym *s; int a; if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); mkfwd(); s = lookup("exit", 0); vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) { for(p = cursym->text; p != P; p = p->link) { a = p->as; if((a == ABL || a == ABX || a == AB || a == ARET) && p->to.type != D_BRANCH && p->to.sym != S) { s = p->to.sym; if(s->text == nil) continue; switch(s->type&SMASK) { default: diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages case STEXT: p->to.offset = s->value; p->to.type = D_BRANCH; p->cond = s->text; continue; } } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = cursym->text; q != P;) { if(c == q->pc) break; if(q->forwd != P && c >= q->forwd->pc) q = q->forwd; else q = q->link; } if(q == P) { diag("branch out of range %d\n%P", c, p); p->to.type = D_NONE; } p->cond = q; } } for(cursym = textp; cursym != nil; cursym = cursym->next) { for(p = cursym->text; p != P; p = p->link) { if(p->cond != P) { p->cond = brloop(p->cond); if(p->cond != P) if(p->to.type == D_BRANCH) p->to.offset = p->cond->pc; } } } }
void patch(void) { int32 c; Prog *p, *q; Sym *s, *gmsym; int32 vexit; if(debug['v']) Bprint(&bso, "%5.2f mkfwd\n", cputime()); Bflush(&bso); mkfwd(); if(debug['v']) Bprint(&bso, "%5.2f patch\n", cputime()); Bflush(&bso); if(flag_shared) { s = lookup("init_array", 0); s->type = SINITARR; s->reachable = 1; s->hide = 1; addaddr(s, lookup(INITENTRY, 0)); } gmsym = lookup("runtime.tlsgm", 0); if(linkmode != LinkExternal) gmsym->reachable = 0; s = lookup("exit", 0); vexit = s->value; for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { if(HEADTYPE == Hwindows) { // Windows // Convert // op n(GS), reg // to // MOVL 0x28(GS), reg // op n(reg), reg // The purpose of this patch is to fix some accesses // to extern register variables (TLS) on Windows, as // a different method is used to access them. if(p->from.type == D_INDIR+D_GS && p->to.type >= D_AX && p->to.type <= D_DI && p->from.offset <= 8) { q = appendp(p); q->from = p->from; q->from.type = D_INDIR + p->to.type; q->to = p->to; q->as = p->as; p->as = AMOVQ; p->from.type = D_INDIR+D_GS; p->from.offset = 0x28; } } if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) { // ELF uses FS instead of GS. if(p->from.type == D_INDIR+D_GS) p->from.type = D_INDIR+D_FS; if(p->to.type == D_INDIR+D_GS) p->to.type = D_INDIR+D_FS; if(p->from.index == D_GS) p->from.index = D_FS; if(p->to.index == D_GS) p->to.index = D_FS; } if(!flag_shared) { // Convert g() or m() accesses of the form // op n(reg)(GS*1), reg // to // op n(GS*1), reg if(p->from.index == D_FS || p->from.index == D_GS) { p->from.type = D_INDIR + p->from.index; p->from.index = D_NONE; } // Convert g() or m() accesses of the form // op reg, n(reg)(GS*1) // to // op reg, n(GS*1) if(p->to.index == D_FS || p->to.index == D_GS) { p->to.type = D_INDIR + p->to.index; p->to.index = D_NONE; } // Convert get_tls access of the form // op runtime.tlsgm(SB), reg // to // NOP if(gmsym != S && p->from.sym == gmsym) { p->as = ANOP; p->from.type = D_NONE; p->to.type = D_NONE; p->from.sym = nil; p->to.sym = nil; continue; } } else { // Convert TLS reads of the form // op n(GS), reg // to // MOVQ $runtime.tlsgm(SB), reg // op n(reg)(GS*1), reg if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) { q = appendp(p); q->to = p->to; q->as = p->as; q->from.type = D_INDIR+p->to.type; q->from.index = p->from.type - D_INDIR; q->from.scale = 1; q->from.offset = p->from.offset; p->as = AMOVQ; p->from.type = D_EXTERN; p->from.sym = gmsym; p->from.offset = 0; } } if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) { s = p->to.sym; if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); if((s->type&SMASK) != STEXT) { /* diag prints TNAME first */ diag("undefined: %s", s->name); s->type = STEXT; s->value = vexit; continue; // avoid more error messages } if(s->text == nil) continue; p->to.type = D_BRANCH; p->to.offset = s->text->pc; p->pcond = s->text; continue; } } if(p->to.type != D_BRANCH) continue; c = p->to.offset; for(q = cursym->text; q != P;) { if(c == q->pc) break; if(q->forwd != P && c >= q->forwd->pc) q = q->forwd; else q = q->link; } if(q == P) { diag("branch out of range in %s (%#ux)\n%P [%s]", TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>"); p->to.type = D_NONE; } p->pcond = q; } for(cursym = textp; cursym != nil; cursym = cursym->next) for(p = cursym->text; p != P; p = p->link) { p->mark = 0; /* initialization for follow */ if(p->pcond != P) { p->pcond = brloop(p->pcond); if(p->pcond != P) if(p->to.type == D_BRANCH) p->to.offset = p->pcond->pc; } } }