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
35
#include "../cmd/8l/8.out.h"
36
#include "../pkg/runtime/stack.h"
67
return p->as == ADATA || p->as == AGLOBL;
73
return p->as == ACALL;
89
settextflag(Prog *p, int f)
95
canuselocaltls(Link *ctxt)
97
switch(ctxt->headtype) {
108
progedit(Link *ctxt, Prog *p)
114
// See obj6.c for discussion of TLS.
115
if(canuselocaltls(ctxt)) {
116
// Reduce TLS initial exec model to TLS local exec model.
119
// ... off(BX)(TLS*1) ...
123
if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
125
p->from.type = D_NONE;
128
if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
129
p->from.type = D_INDIR+D_TLS;
131
p->from.index = D_NONE;
133
if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
134
p->to.type = D_INDIR+D_TLS;
136
p->to.index = D_NONE;
139
// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
142
// becomes the sequence
144
// MOVL off(BX)(TLS*1), BX
145
// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
146
if(p->as == AMOVL && p->from.type == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
147
q = appendp(ctxt, p);
150
q->from.type = D_INDIR + p->to.type;
151
q->from.index = D_TLS;
152
q->from.scale = 2; // TODO: use 1
154
p->from.type = D_TLS;
155
p->from.index = D_NONE;
161
if(ctxt->headtype == Hplan9) {
162
if(p->from.scale == 1 && p->from.index == D_TLS)
164
if(p->to.scale == 1 && p->to.index == D_TLS)
168
// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
173
if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
174
p->to.type = D_BRANCH;
178
// Rewrite float constants to values stored in memory.
196
if(p->from.type == D_FCONST) {
199
f32 = p->from.u.dval;
200
memmove(&i32, &f32, 4);
201
sprint(literal, "$f32.%08ux", (uint32)i32);
202
s = linklookup(ctxt, literal, 0);
205
adduint32(ctxt, s, i32);
208
p->from.type = D_EXTERN;
230
if(p->from.type == D_FCONST) {
232
memmove(&i64, &p->from.u.dval, 8);
233
sprint(literal, "$f64.%016llux", (uvlong)i64);
234
s = linklookup(ctxt, literal, 0);
237
adduint64(ctxt, s, i64);
240
p->from.type = D_EXTERN;
253
p = emallocz(sizeof(*p));
258
static Prog* load_g_cx(Link*, Prog*);
259
static Prog* stacksplit(Link*, Prog*, int32, int, Prog**);
262
addstacksplit(Link *ctxt, LSym *cursym)
265
int32 autoffset, deltasp;
268
if(ctxt->symmorestack[0] == nil) {
269
ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
270
ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
273
if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
274
ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
276
ctxt->cursym = cursym;
278
if(cursym->text == nil || cursym->text->link == nil)
282
autoffset = p->to.offset;
286
cursym->locals = autoffset;
287
cursym->args = p->to.offset2;
291
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
292
p = appendp(ctxt, p);
293
p = load_g_cx(ctxt, p); // load g into CX
295
if(!(cursym->text->from.scale & NOSPLIT))
296
p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
299
p = appendp(ctxt, p);
301
p->from.type = D_CONST;
302
p->from.offset = autoffset;
303
p->spadj = autoffset;
305
// zero-byte stack adjustment.
306
// Insert a fake non-zero adjustment so that stkcheck can
307
// recognize the end of the stack-splitting prolog.
308
p = appendp(ctxt, p);
310
p->spadj = -ctxt->arch->ptrsize;
311
p = appendp(ctxt, p);
313
p->spadj = ctxt->arch->ptrsize;
319
if(cursym->text->from.scale & WRAPPER) {
320
// g->panicwrap += autoffset + ctxt->arch->ptrsize;
321
p = appendp(ctxt, p);
323
p->from.type = D_CONST;
324
p->from.offset = autoffset + ctxt->arch->ptrsize;
325
p->to.type = D_INDIR+D_CX;
326
p->to.offset = 2*ctxt->arch->ptrsize;
329
if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
330
// 8l -Z means zero the stack frame on entry.
331
// This slows down function calls but can help avoid
332
// false positives in garbage collection.
333
p = appendp(ctxt, p);
338
p = appendp(ctxt, p);
340
p->from.type = D_CONST;
341
p->from.offset = autoffset/4;
344
p = appendp(ctxt, p);
346
p->from.type = D_CONST;
350
p = appendp(ctxt, p);
353
p = appendp(ctxt, p);
357
for(; p != nil; p = p->link) {
360
p->from.offset += deltasp;
362
p->from.offset += deltasp + 4;
365
p->to.offset += deltasp;
367
p->to.offset += deltasp + 4;
396
if(autoffset != deltasp)
397
ctxt->diag("unbalanced PUSH/POP");
399
if(cursym->text->from.scale & WRAPPER) {
400
p = load_g_cx(ctxt, p);
401
p = appendp(ctxt, p);
402
// g->panicwrap -= autoffset + ctxt->arch->ptrsize;
404
p->from.type = D_CONST;
405
p->from.offset = autoffset + ctxt->arch->ptrsize;
406
p->to.type = D_INDIR+D_CX;
407
p->to.offset = 2*ctxt->arch->ptrsize;
408
p = appendp(ctxt, p);
414
p->from.type = D_CONST;
415
p->from.offset = -autoffset;
416
p->spadj = -autoffset;
417
p = appendp(ctxt, p);
419
// If there are instructions following
420
// this ARET, they come from a branch
421
// with the same stackframe, so undo
423
p->spadj = +autoffset;
425
if(p->to.sym) // retjmp
430
// Append code to p to load g into cx.
431
// Overwrites p with the first instruction (no first appendp).
432
// Overwriting p is unusual but it lets use this in both the
433
// prologue (caller must call appendp first) and in the epilogue.
434
// Returns last new instruction.
436
load_g_cx(Link *ctxt, Prog *p)
441
p->from.type = D_INDIR+D_TLS;
447
while(p->link != next)
450
if(p->from.index == D_TLS)
456
// Append code to p to check for stack split.
457
// Appends to (does not overwrite) p.
458
// Assumes g is in CX.
459
// Returns last new instruction.
460
// On return, *jmpok is the instruction that should jump
461
// to the stack frame allocation if no split is needed.
463
stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
468
if(ctxt->debugstack) {
469
// 8l -K means check not only for stack
470
// overflow but stack underflow.
471
// On underflow, INT 3 (breakpoint).
472
// Underflow itself is rare but this also
473
// catches out-of-sync stack guard info.
474
p = appendp(ctxt, p);
476
p->from.type = D_INDIR+D_CX;
480
p = appendp(ctxt, p);
482
p->to.type = D_BRANCH;
486
p = appendp(ctxt, p);
488
p->from.type = D_CONST;
491
p = appendp(ctxt, p);
497
if(framesize <= StackSmall) {
498
// small stack: SP <= stackguard
499
// CMPL SP, stackguard
500
p = appendp(ctxt, p);
503
p->to.type = D_INDIR+D_CX;
504
} else if(framesize <= StackBig) {
505
// large stack: SP-framesize <= stackguard-StackSmall
506
// LEAL -(framesize-StackSmall)(SP), AX
507
// CMPL AX, stackguard
508
p = appendp(ctxt, p);
510
p->from.type = D_INDIR+D_SP;
511
p->from.offset = -(framesize-StackSmall);
514
p = appendp(ctxt, p);
517
p->to.type = D_INDIR+D_CX;
519
// Such a large stack we need to protect against wraparound
520
// if SP is close to zero.
521
// SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
522
// The +StackGuard on both sides is required to keep the left side positive:
523
// SP is allowed to be slightly below stackguard. See stack.h.
525
// Preemption sets stackguard to StackPreempt, a very large value.
526
// That breaks the math above, so we have to check for that explicitly.
527
// MOVL stackguard, CX
528
// CMPL CX, $StackPreempt
529
// JEQ label-of-call-to-morestack
530
// LEAL StackGuard(SP), AX
531
// SUBL stackguard, AX
532
// CMPL AX, $(framesize+(StackGuard-StackSmall))
533
p = appendp(ctxt, p);
535
p->from.type = D_INDIR+D_CX;
539
p = appendp(ctxt, p);
542
p->to.type = D_CONST;
543
p->to.offset = (uint32)StackPreempt;
545
p = appendp(ctxt, p);
547
p->to.type = D_BRANCH;
550
p = appendp(ctxt, p);
552
p->from.type = D_INDIR+D_SP;
553
p->from.offset = StackGuard;
556
p = appendp(ctxt, p);
562
p = appendp(ctxt, p);
565
p->to.type = D_CONST;
566
p->to.offset = framesize+(StackGuard-StackSmall);
570
p = appendp(ctxt, p);
572
p->to.type = D_BRANCH;
576
p = appendp(ctxt, p); // save frame size in DI
579
p->from.type = D_CONST;
581
// If we ask for more stack, we'll get a minimum of StackMin bytes.
582
// We need a stack frame large enough to hold the top-of-stack data,
583
// the function arguments+results, our caller's PC, our frame,
584
// a word for the return PC of the next call, and then the StackLimit bytes
585
// that must be available on entry to any function called from a function
586
// that did a stack check. If StackMin is enough, don't ask for a specific
587
// amount: then we can use the custom functions and save a few
589
if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
590
p->from.offset = (framesize+7) & ~7LL;
592
arg = ctxt->cursym->text->to.offset2;
593
if(arg == 1) // special marker for known 0
596
ctxt->diag("misaligned argument size in stack split");
597
p = appendp(ctxt, p); // save arg size in AX
600
p->from.type = D_CONST;
601
p->from.offset = arg;
603
p = appendp(ctxt, p);
605
p->to.type = D_BRANCH;
606
p->to.sym = ctxt->symmorestack[noctxt];
608
p = appendp(ctxt, p);
610
p->to.type = D_BRANCH;
611
p->pcond = ctxt->cursym->text->link;
622
static void xfol(Link*, Prog*, Prog**);
625
follow(Link *ctxt, LSym *s)
627
Prog *firstp, *lastp;
631
firstp = ctxt->arch->prg();
633
xfol(ctxt, s->text, &lastp);
635
s->text = firstp->link;
674
case AJEQ: return AJNE;
675
case AJNE: return AJEQ;
676
case AJLE: return AJGT;
677
case AJLS: return AJHI;
678
case AJLT: return AJGE;
679
case AJMI: return AJPL;
680
case AJGE: return AJLT;
681
case AJPL: return AJMI;
682
case AJGT: return AJLE;
683
case AJHI: return AJLS;
684
case AJCS: return AJCC;
685
case AJCC: return AJCS;
686
case AJPS: return AJPC;
687
case AJPC: return AJPS;
688
case AJOS: return AJOC;
689
case AJOC: return AJOS;
691
sysfatal("unknown relation: %s", anames8[a]);
696
xfol(Link *ctxt, Prog *p, Prog **last)
706
if((q = p->pcond) != nil && q->as != ATEXT) {
707
/* mark instruction as done and continue layout at target of jump */
715
* p goes here, but already used it elsewhere.
716
* copy up to 4 instructions or else branch to other copy.
718
for(i=0,q=p; i<4; i++,q=q->link) {
728
if(nofollow(a) || pushpop(a))
729
break; // NOTE(rsc): arm does goto copy
730
if(q->pcond == nil || q->pcond->mark)
732
if(a == ACALL || a == ALOOP)
744
if(q->as != a || q->pcond == nil || q->pcond->mark)
747
q->as = relinv(q->as);
751
xfol(ctxt, q->link, last);
758
q = ctxt->arch->prg();
760
q->lineno = p->lineno;
761
q->to.type = D_BRANCH;
762
q->to.offset = p->pc;
773
/* continue loop with what comes after p */
776
if(p->pcond != nil && a != ACALL) {
778
* some kind of conditional branch.
779
* recurse to follow one path.
780
* continue loop on the other.
782
if((q = brchain(ctxt, p->pcond)) != nil)
784
if((q = brchain(ctxt, p->link)) != nil)
786
if(p->from.type == D_CONST) {
787
if(p->from.offset == 1) {
789
* expect conditional jump to be taken.
790
* rewrite so that's the fall-through case.
806
xfol(ctxt, p->link, last);
820
.addstacksplit = addstacksplit,
822
.datasize = datasize,
827
.progedit = progedit,
828
.settextflag = settextflag,
830
.textflag = textflag,
838
.D_BRANCH = D_BRANCH,
840
.D_EXTERN = D_EXTERN,
841
.D_FCONST = D_FCONST,
844
.D_SCONST = D_SCONST,
845
.D_STATIC = D_STATIC,
850
.AFUNCDATA = AFUNCDATA,
858
.AUSEFIELD = AUSEFIELD,