1
// Inferno utils/8l/pass.c
2
// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
4
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
5
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6
// Portions Copyright © 1997-1999 Vita Nuova Limited
7
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8
// Portions Copyright © 2004,2006 Bruce Ellis
9
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11
// Portions Copyright © 2009 The Go Authors. All rights reserved.
13
// Permission is hereby granted, free of charge, to any person obtaining a copy
14
// of this software and associated documentation files (the "Software"), to deal
15
// in the Software without restriction, including without limitation the rights
16
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
// copies of the Software, and to permit persons to whom the Software is
18
// furnished to do so, subject to the following conditions:
20
// The above copyright notice and this permission notice shall be included in
21
// all copies or substantial portions of the Software.
23
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
// Code and data passes.
34
#include "../ld/lib.h"
35
#include "../../pkg/runtime/stack.h"
37
static void xfol(Prog*, Prog**);
45
if(p == P || p->as != AJMP)
58
Bprint(&bso, "%5.2f follow\n", cputime());
61
for(cursym = textp; cursym != nil; cursym = cursym->next) {
64
xfol(cursym->text, &lastp);
66
cursym->text = firstp->link;
102
xfol(Prog *p, Prog **last)
112
if((q = p->pcond) != P && q->as != ATEXT) {
113
/* mark instruction as done and continue layout at target of jump */
121
* p goes here, but already used it elsewhere.
122
* copy up to 4 instructions or else branch to other copy.
124
for(i=0,q=p; i<4; i++,q=q->link) {
134
if(nofollow(a) || pushpop(a))
135
break; // NOTE(rsc): arm does goto copy
136
if(q->pcond == P || q->pcond->mark)
138
if(a == ACALL || a == ALOOP)
150
if(q->as != a || q->pcond == P || q->pcond->mark)
153
q->as = relinv(q->as);
167
q->to.type = D_BRANCH;
168
q->to.offset = p->pc;
179
/* continue loop with what comes after p */
182
if(p->pcond != P && a != ACALL) {
184
* some kind of conditional branch.
185
* recurse to follow one path.
186
* continue loop on the other.
188
if((q = brchain(p->pcond)) != P)
190
if((q = brchain(p->link)) != P)
192
if(p->from.type == D_CONST) {
193
if(p->from.offset == 1) {
195
* expect conditional jump to be taken.
196
* rewrite so that's the fall-through case.
227
case AJEQ: return AJNE;
228
case AJNE: return AJEQ;
229
case AJLE: return AJGT;
230
case AJLS: return AJHI;
231
case AJLT: return AJGE;
232
case AJMI: return AJPL;
233
case AJGE: return AJLT;
234
case AJPL: return AJMI;
235
case AJGT: return AJLE;
236
case AJHI: return AJLS;
237
case AJCS: return AJCC;
238
case AJCC: return AJCS;
239
case AJPS: return AJPC;
240
case AJPC: return AJPS;
241
case AJOS: return AJOC;
242
case AJOC: return AJOS;
244
diag("unknown relation: %s in %s", anames[a], TNAME);
258
Bprint(&bso, "%5.2f mkfwd\n", cputime());
262
Bprint(&bso, "%5.2f patch\n", cputime());
264
s = lookup("exit", 0);
268
if(HEADTYPE == Hplan9x32)
269
plan9_tos = lookup("_tos", 0);
271
for(cursym = textp; cursym != nil; cursym = cursym->next) {
272
for(p = cursym->text; p != P; p = p->link) {
273
if(HEADTYPE == Hwindows) {
277
// MOVL 0x14(FS), reg
279
// The purpose of this patch is to fix some accesses
280
// to extern register variables (TLS) on Windows, as
281
// a different method is used to access them.
282
if(p->from.type == D_INDIR+D_GS
283
&& p->to.type >= D_AX && p->to.type <= D_DI) {
286
q->from.type = D_INDIR + p->to.type;
290
p->from.type = D_INDIR+D_FS;
291
p->from.offset = 0x14;
294
if(HEADTYPE == Hlinux) {
295
// Running binaries under Xen requires using
297
// and then off(reg) instead of saying off(GS) directly
298
// when the offset is negative.
299
// In external mode we just produce a reloc.
300
if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
301
&& p->to.type >= D_AX && p->to.type <= D_DI) {
302
if(linkmode != LinkExternal) {
305
q->from.type = D_INDIR + p->to.type;
309
p->from.type = D_INDIR+D_GS;
312
// Add signals to relocate.
313
p->from.index = D_GS;
318
if(HEADTYPE == Hplan9x32) {
319
if(p->from.type == D_INDIR+D_GS
320
&& p->to.type >= D_AX && p->to.type <= D_DI) {
323
q->from.type = D_INDIR + p->to.type;
327
p->from.type = D_EXTERN;
328
p->from.sym = plan9_tos;
332
if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
334
if(p->to.type == D_INDIR+D_ADDR) {
335
/* skip check if this is an indirect call (CALL *symbol(SB)) */
339
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
340
if((s->type&SMASK) != STEXT) {
341
/* diag prints TNAME first */
342
diag("undefined: %s", s->name);
345
continue; // avoid more error messages
349
p->to.type = D_BRANCH;
350
p->to.offset = s->text->pc;
355
if(p->to.type != D_BRANCH)
358
for(q = cursym->text; q != P;) {
361
if(q->forwd != P && c >= q->forwd->pc)
367
diag("branch out of range in %s (%#ux)\n%P [%s]",
368
TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
375
for(cursym = textp; cursym != nil; cursym = cursym->next) {
376
if(cursym->text == nil || cursym->p != nil)
379
for(p = cursym->text; p != P; p = p->link) {
380
p->mark = 0; /* initialization for follow */
382
p->pcond = brloop(p->pcond);
384
if(p->to.type == D_BRANCH)
385
p->to.offset = p->pcond->pc;
398
for(q = p; q != P; q = q->pcond) {
408
static Prog* load_g_cx(Prog*);
409
static Prog* stacksplit(Prog*, int32, Prog**);
411
static Sym *plan9_tos;
412
static Prog *pmorestack;
413
static Sym *symmorestack;
419
int32 autoffset, deltasp;
423
symmorestack = lookup("runtime.morestack", 0);
425
if(symmorestack->type != STEXT)
426
diag("runtime.morestack not defined");
428
pmorestack = symmorestack->text;
429
symmorestack->text->from.scale |= NOSPLIT;
433
if(HEADTYPE == Hplan9x32)
434
plan9_tos = lookup("_tos", 0);
436
for(cursym = textp; cursym != nil; cursym = cursym->next) {
437
if(cursym->text == nil || cursym->text->link == nil)
441
autoffset = p->to.offset;
447
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
449
p = load_g_cx(p); // load g into CX
451
if(!(cursym->text->from.scale & NOSPLIT))
452
p = stacksplit(p, autoffset, &q); // emit split check
457
p->from.type = D_CONST;
458
p->from.offset = autoffset;
459
p->spadj = autoffset;
461
// zero-byte stack adjustment.
462
// Insert a fake non-zero adjustment so that stkcheck can
463
// recognize the end of the stack-splitting prolog.
475
if(cursym->text->from.scale & WRAPPER) {
476
// g->panicwrap += autoffset + PtrSize;
479
p->from.type = D_CONST;
480
p->from.offset = autoffset + PtrSize;
481
p->to.type = D_INDIR+D_CX;
482
p->to.offset = 2*PtrSize;
485
if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
486
// 8l -Z means zero the stack frame on entry.
487
// This slows down function calls but can help avoid
488
// false positives in garbage collection.
496
p->from.type = D_CONST;
497
p->from.offset = autoffset/4;
502
p->from.type = D_CONST;
513
for(; p != P; p = p->link) {
516
p->from.offset += deltasp;
518
p->from.offset += deltasp + 4;
521
p->to.offset += deltasp;
523
p->to.offset += deltasp + 4;
552
if(autoffset != deltasp)
553
diag("unbalanced PUSH/POP");
555
if(cursym->text->from.scale & WRAPPER) {
558
// g->panicwrap -= autoffset + PtrSize;
560
p->from.type = D_CONST;
561
p->from.offset = autoffset + PtrSize;
562
p->to.type = D_INDIR+D_CX;
563
p->to.offset = 2*PtrSize;
570
p->from.type = D_CONST;
571
p->from.offset = -autoffset;
572
p->spadj = -autoffset;
575
// If there are instructions following
576
// this ARET, they come from a branch
577
// with the same stackframe, so undo
579
p->spadj = +autoffset;
581
if(p->to.sym) // retjmp
587
// Append code to p to load g into cx.
588
// Overwrites p with the first instruction (no first appendp).
589
// Overwriting p is unusual but it lets use this in both the
590
// prologue (caller must call appendp first) and in the epilogue.
591
// Returns last new instruction.
598
p->from.type = D_INDIR+D_FS;
599
p->from.offset = 0x14;
604
p->from.type = D_INDIR+D_CX;
610
if(linkmode != LinkExternal) {
612
p->from.type = D_INDIR+D_GS;
618
p->from.type = D_INDIR+D_CX;
619
p->from.offset = tlsoffset + 0;
623
p->from.type = D_INDIR+D_GS;
624
p->from.offset = tlsoffset + 0;
626
p->from.index = D_GS;
633
p->from.type = D_EXTERN;
634
p->from.sym = plan9_tos;
639
p->from.type = D_INDIR+D_CX;
640
p->from.offset = tlsoffset + 0;
646
p->from.type = D_INDIR+D_GS;
647
p->from.offset = tlsoffset + 0;
653
// Append code to p to check for stack split.
654
// Appends to (does not overwrite) p.
655
// Assumes g is in CX.
656
// Returns last new instruction.
657
// On return, *jmpok is the instruction that should jump
658
// to the stack frame allocation if no split is needed.
660
stacksplit(Prog *p, int32 framesize, Prog **jmpok)
666
// 8l -K means check not only for stack
667
// overflow but stack underflow.
668
// On underflow, INT 3 (breakpoint).
669
// Underflow itself is rare but this also
670
// catches out-of-sync stack guard info.
673
p->from.type = D_INDIR+D_CX;
679
p->to.type = D_BRANCH;
685
p->from.type = D_CONST;
694
if(framesize <= StackSmall) {
695
// small stack: SP <= stackguard
696
// CMPL SP, stackguard
700
p->to.type = D_INDIR+D_CX;
701
} else if(framesize <= StackBig) {
702
// large stack: SP-framesize <= stackguard-StackSmall
703
// LEAL -(framesize-StackSmall)(SP), AX
704
// CMPL AX, stackguard
707
p->from.type = D_INDIR+D_SP;
708
p->from.offset = -(framesize-StackSmall);
714
p->to.type = D_INDIR+D_CX;
716
// Such a large stack we need to protect against wraparound
717
// if SP is close to zero.
718
// SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
719
// The +StackGuard on both sides is required to keep the left side positive:
720
// SP is allowed to be slightly below stackguard. See stack.h.
722
// Preemption sets stackguard to StackPreempt, a very large value.
723
// That breaks the math above, so we have to check for that explicitly.
724
// MOVL stackguard, CX
725
// CMPL CX, $StackPreempt
726
// JEQ label-of-call-to-morestack
727
// LEAL StackGuard(SP), AX
728
// SUBL stackguard, AX
729
// CMPL AX, $(framesize+(StackGuard-StackSmall))
732
p->from.type = D_INDIR+D_CX;
739
p->to.type = D_CONST;
740
p->to.offset = (uint32)StackPreempt;
744
p->to.type = D_BRANCH;
749
p->from.type = D_INDIR+D_SP;
750
p->from.offset = StackGuard;
762
p->to.type = D_CONST;
763
p->to.offset = framesize+(StackGuard-StackSmall);
769
p->to.type = D_BRANCH;
773
p = appendp(p); // save frame size in DI
776
p->from.type = D_CONST;
778
// If we ask for more stack, we'll get a minimum of StackMin bytes.
779
// We need a stack frame large enough to hold the top-of-stack data,
780
// the function arguments+results, our caller's PC, our frame,
781
// a word for the return PC of the next call, and then the StackLimit bytes
782
// that must be available on entry to any function called from a function
783
// that did a stack check. If StackMin is enough, don't ask for a specific
784
// amount: then we can use the custom functions and save a few
786
if(StackTop + cursym->text->to.offset2 + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
787
p->from.offset = (framesize+7) & ~7LL;
789
arg = cursym->text->to.offset2;
790
if(arg == 1) // special marker for known 0
793
diag("misaligned argument size in stack split");
794
p = appendp(p); // save arg size in AX
797
p->from.type = D_CONST;
798
p->from.offset = arg;
802
p->to.type = D_BRANCH;
803
p->pcond = pmorestack;
804
p->to.sym = symmorestack;
808
p->to.type = D_BRANCH;
809
p->pcond = cursym->text->link;
828
while(*s == ' ' || *s == '\t')
830
if(*s == '-' || *s == '+') {
833
while(*s == ' ' || *s == '\t')
836
if(s[0]=='0' && s[1]){
837
if(s[1]=='x' || s[1]=='X'){
840
if(*s >= '0' && *s <= '9')
841
n = n*16 + *s++ - '0';
842
else if(*s >= 'a' && *s <= 'f')
843
n = n*16 + *s++ - 'a' + 10;
844
else if(*s >= 'A' && *s <= 'F')
845
n = n*16 + *s++ - 'A' + 10;
850
while(*s >= '0' && *s <= '7')
851
n = n*8 + *s++ - '0';
853
while(*s >= '0' && *s <= '9')
854
n = n*10 + *s++ - '0';