~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/liblink/obj8.c

  • Committer: Package Import Robot
  • Author(s): Serge Hallyn
  • Date: 2014-11-18 15:12:26 UTC
  • mfrom: (14.2.12 vivid-proposed)
  • Revision ID: package-import@ubuntu.com-20141118151226-zug7vn93mn3dtiz3
Tags: 2:1.3.2-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - Support co-installability with gccgo-go tool:
    - d/rules,golang-go.install: Rename bin/go -> bin/golang-go
    - d/golang-go.{postinst,prerm}: Install/remove /usr/bin/go using
      alternatives.
  - d/copyright: Amendments for full compiliance with copyright format.
  - d/control: Demote golang-go.tools to Suggests to support Ubuntu MIR.
  - dropped patches (now upstream):
    - d/p/issue27650045_40001_50001.diff
    - d/p/issue28050043_60001_70001.diff
    - d/p/issue54790044_100001_110001.diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Inferno utils/8l/pass.c
 
2
// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
 
3
//
 
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.
 
12
//
 
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:
 
19
//
 
20
// The above copyright notice and this permission notice shall be included in
 
21
// all copies or substantial portions of the Software.
 
22
//
 
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
 
29
// THE SOFTWARE.
 
30
 
 
31
#include <u.h>
 
32
#include <libc.h>
 
33
#include <bio.h>
 
34
#include <link.h>
 
35
#include "../cmd/8l/8.out.h"
 
36
#include "../pkg/runtime/stack.h"
 
37
 
 
38
static Prog zprg = {
 
39
        .back = 2,
 
40
        .as = AGOK,
 
41
        .from = {
 
42
                .type = D_NONE,
 
43
                .index = D_NONE,
 
44
                .scale = 1,
 
45
        },
 
46
        .to = {
 
47
                .type = D_NONE,
 
48
                .index = D_NONE,
 
49
                .scale = 1,
 
50
        },
 
51
};
 
52
 
 
53
static int
 
54
symtype(Addr *a)
 
55
{
 
56
        int t;
 
57
 
 
58
        t = a->type;
 
59
        if(t == D_ADDR)
 
60
                t = a->index;
 
61
        return t;
 
62
}
 
63
 
 
64
static int
 
65
isdata(Prog *p)
 
66
{
 
67
        return p->as == ADATA || p->as == AGLOBL;
 
68
}
 
69
 
 
70
static int
 
71
iscall(Prog *p)
 
72
{
 
73
        return p->as == ACALL;
 
74
}
 
75
 
 
76
static int
 
77
datasize(Prog *p)
 
78
{
 
79
        return p->from.scale;
 
80
}
 
81
 
 
82
static int
 
83
textflag(Prog *p)
 
84
{
 
85
        return p->from.scale;
 
86
}
 
87
 
 
88
static void
 
89
settextflag(Prog *p, int f)
 
90
{
 
91
        p->from.scale = f;
 
92
}
 
93
 
 
94
static int
 
95
canuselocaltls(Link *ctxt)
 
96
{
 
97
        switch(ctxt->headtype) {
 
98
        case Hlinux:
 
99
        case Hnacl:
 
100
        case Hplan9:
 
101
        case Hwindows:
 
102
                return 0;
 
103
        }
 
104
        return 1;
 
105
}
 
106
 
 
107
static void
 
108
progedit(Link *ctxt, Prog *p)
 
109
{
 
110
        char literal[64];
 
111
        LSym *s;
 
112
        Prog *q;
 
113
        
 
114
        // See obj6.c for discussion of TLS.
 
115
        if(canuselocaltls(ctxt)) {
 
116
                // Reduce TLS initial exec model to TLS local exec model.
 
117
                // Sequences like
 
118
                //      MOVL TLS, BX
 
119
                //      ... off(BX)(TLS*1) ...
 
120
                // become
 
121
                //      NOP
 
122
                //      ... off(TLS) ...
 
123
                if(p->as == AMOVL && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
 
124
                        p->as = ANOP;
 
125
                        p->from.type = D_NONE;
 
126
                        p->to.type = D_NONE;
 
127
                }
 
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;
 
130
                        p->from.scale = 0;
 
131
                        p->from.index = D_NONE;
 
132
                }
 
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;
 
135
                        p->to.scale = 0;
 
136
                        p->to.index = D_NONE;
 
137
                }
 
138
        } else {
 
139
                // As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
 
140
                // The instruction
 
141
                //      MOVL off(TLS), BX
 
142
                // becomes the sequence
 
143
                //      MOVL TLS, BX
 
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);
 
148
                        q->as = p->as;
 
149
                        q->from = p->from;
 
150
                        q->from.type = D_INDIR + p->to.type;
 
151
                        q->from.index = D_TLS;
 
152
                        q->from.scale = 2; // TODO: use 1
 
153
                        q->to = p->to;
 
154
                        p->from.type = D_TLS;
 
155
                        p->from.index = D_NONE;
 
156
                        p->from.offset = 0;
 
157
                }
 
158
        }
 
159
 
 
160
        // TODO: Remove.
 
161
        if(ctxt->headtype == Hplan9) {
 
162
                if(p->from.scale == 1 && p->from.index == D_TLS)
 
163
                        p->from.scale = 2;
 
164
                if(p->to.scale == 1 && p->to.index == D_TLS)
 
165
                        p->to.scale = 2;
 
166
        }
 
167
 
 
168
        // Rewrite CALL/JMP/RET to symbol as D_BRANCH.
 
169
        switch(p->as) {
 
170
        case ACALL:
 
171
        case AJMP:
 
172
        case ARET:
 
173
                if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
 
174
                        p->to.type = D_BRANCH;
 
175
                break;
 
176
        }
 
177
 
 
178
        // Rewrite float constants to values stored in memory.
 
179
        switch(p->as) {
 
180
        case AFMOVF:
 
181
        case AFADDF:
 
182
        case AFSUBF:
 
183
        case AFSUBRF:
 
184
        case AFMULF:
 
185
        case AFDIVF:
 
186
        case AFDIVRF:
 
187
        case AFCOMF:
 
188
        case AFCOMFP:
 
189
        case AMOVSS:
 
190
        case AADDSS:
 
191
        case ASUBSS:
 
192
        case AMULSS:
 
193
        case ADIVSS:
 
194
        case ACOMISS:
 
195
        case AUCOMISS:
 
196
                if(p->from.type == D_FCONST) {
 
197
                        int32 i32;
 
198
                        float32 f32;
 
199
                        f32 = p->from.u.dval;
 
200
                        memmove(&i32, &f32, 4);
 
201
                        sprint(literal, "$f32.%08ux", (uint32)i32);
 
202
                        s = linklookup(ctxt, literal, 0);
 
203
                        if(s->type == 0) {
 
204
                                s->type = SRODATA;
 
205
                                adduint32(ctxt, s, i32);
 
206
                                s->reachable = 0;
 
207
                        }
 
208
                        p->from.type = D_EXTERN;
 
209
                        p->from.sym = s;
 
210
                        p->from.offset = 0;
 
211
                }
 
212
                break;
 
213
 
 
214
        case AFMOVD:
 
215
        case AFADDD:
 
216
        case AFSUBD:
 
217
        case AFSUBRD:
 
218
        case AFMULD:
 
219
        case AFDIVD:
 
220
        case AFDIVRD:
 
221
        case AFCOMD:
 
222
        case AFCOMDP:
 
223
        case AMOVSD:
 
224
        case AADDSD:
 
225
        case ASUBSD:
 
226
        case AMULSD:
 
227
        case ADIVSD:
 
228
        case ACOMISD:
 
229
        case AUCOMISD:
 
230
                if(p->from.type == D_FCONST) {
 
231
                        int64 i64;
 
232
                        memmove(&i64, &p->from.u.dval, 8);
 
233
                        sprint(literal, "$f64.%016llux", (uvlong)i64);
 
234
                        s = linklookup(ctxt, literal, 0);
 
235
                        if(s->type == 0) {
 
236
                                s->type = SRODATA;
 
237
                                adduint64(ctxt, s, i64);
 
238
                                s->reachable = 0;
 
239
                        }
 
240
                        p->from.type = D_EXTERN;
 
241
                        p->from.sym = s;
 
242
                        p->from.offset = 0;
 
243
                }
 
244
                break;
 
245
        }
 
246
}
 
247
 
 
248
static Prog*
 
249
prg(void)
 
250
{
 
251
        Prog *p;
 
252
 
 
253
        p = emallocz(sizeof(*p));
 
254
        *p = zprg;
 
255
        return p;
 
256
}
 
257
 
 
258
static Prog*    load_g_cx(Link*, Prog*);
 
259
static Prog*    stacksplit(Link*, Prog*, int32, int, Prog**);
 
260
 
 
261
static void
 
262
addstacksplit(Link *ctxt, LSym *cursym)
 
263
{
 
264
        Prog *p, *q;
 
265
        int32 autoffset, deltasp;
 
266
        int a;
 
267
 
 
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);
 
271
        }
 
272
 
 
273
        if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
 
274
                ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
 
275
 
 
276
        ctxt->cursym = cursym;
 
277
 
 
278
        if(cursym->text == nil || cursym->text->link == nil)
 
279
                return;
 
280
 
 
281
        p = cursym->text;
 
282
        autoffset = p->to.offset;
 
283
        if(autoffset < 0)
 
284
                autoffset = 0;
 
285
        
 
286
        cursym->locals = autoffset;
 
287
        cursym->args = p->to.offset2;
 
288
 
 
289
        q = nil;
 
290
 
 
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
 
294
        }
 
295
        if(!(cursym->text->from.scale & NOSPLIT))
 
296
                p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
 
297
 
 
298
        if(autoffset) {
 
299
                p = appendp(ctxt, p);
 
300
                p->as = AADJSP;
 
301
                p->from.type = D_CONST;
 
302
                p->from.offset = autoffset;
 
303
                p->spadj = autoffset;
 
304
        } else {
 
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);
 
309
                p->as = ANOP;
 
310
                p->spadj = -ctxt->arch->ptrsize;
 
311
                p = appendp(ctxt, p);
 
312
                p->as = ANOP;
 
313
                p->spadj = ctxt->arch->ptrsize;
 
314
        }
 
315
        if(q != nil)
 
316
                q->pcond = p;
 
317
        deltasp = autoffset;
 
318
        
 
319
        if(cursym->text->from.scale & WRAPPER) {
 
320
                // g->panicwrap += autoffset + ctxt->arch->ptrsize;
 
321
                p = appendp(ctxt, p);
 
322
                p->as = AADDL;
 
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;
 
327
        }
 
328
        
 
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);
 
334
                p->as = AMOVL;
 
335
                p->from.type = D_SP;
 
336
                p->to.type = D_DI;
 
337
                
 
338
                p = appendp(ctxt, p);
 
339
                p->as = AMOVL;
 
340
                p->from.type = D_CONST;
 
341
                p->from.offset = autoffset/4;
 
342
                p->to.type = D_CX;
 
343
                
 
344
                p = appendp(ctxt, p);
 
345
                p->as = AMOVL;
 
346
                p->from.type = D_CONST;
 
347
                p->from.offset = 0;
 
348
                p->to.type = D_AX;
 
349
                
 
350
                p = appendp(ctxt, p);
 
351
                p->as = AREP;
 
352
                
 
353
                p = appendp(ctxt, p);
 
354
                p->as = ASTOSL;
 
355
        }
 
356
        
 
357
        for(; p != nil; p = p->link) {
 
358
                a = p->from.type;
 
359
                if(a == D_AUTO)
 
360
                        p->from.offset += deltasp;
 
361
                if(a == D_PARAM)
 
362
                        p->from.offset += deltasp + 4;
 
363
                a = p->to.type;
 
364
                if(a == D_AUTO)
 
365
                        p->to.offset += deltasp;
 
366
                if(a == D_PARAM)
 
367
                        p->to.offset += deltasp + 4;
 
368
 
 
369
                switch(p->as) {
 
370
                default:
 
371
                        continue;
 
372
                case APUSHL:
 
373
                case APUSHFL:
 
374
                        deltasp += 4;
 
375
                        p->spadj = 4;
 
376
                        continue;
 
377
                case APUSHW:
 
378
                case APUSHFW:
 
379
                        deltasp += 2;
 
380
                        p->spadj = 2;
 
381
                        continue;
 
382
                case APOPL:
 
383
                case APOPFL:
 
384
                        deltasp -= 4;
 
385
                        p->spadj = -4;
 
386
                        continue;
 
387
                case APOPW:
 
388
                case APOPFW:
 
389
                        deltasp -= 2;
 
390
                        p->spadj = -2;
 
391
                        continue;
 
392
                case ARET:
 
393
                        break;
 
394
                }
 
395
 
 
396
                if(autoffset != deltasp)
 
397
                        ctxt->diag("unbalanced PUSH/POP");
 
398
 
 
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;
 
403
                        p->as = ASUBL;
 
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);
 
409
                        p->as = ARET;
 
410
                }
 
411
 
 
412
                if(autoffset) {
 
413
                        p->as = AADJSP;
 
414
                        p->from.type = D_CONST;
 
415
                        p->from.offset = -autoffset;
 
416
                        p->spadj = -autoffset;
 
417
                        p = appendp(ctxt, p);
 
418
                        p->as = ARET;
 
419
                        // If there are instructions following
 
420
                        // this ARET, they come from a branch
 
421
                        // with the same stackframe, so undo
 
422
                        // the cleanup.
 
423
                        p->spadj = +autoffset;
 
424
                }
 
425
                if(p->to.sym) // retjmp
 
426
                        p->as = AJMP;
 
427
        }
 
428
}
 
429
 
 
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.
 
435
static Prog*
 
436
load_g_cx(Link *ctxt, Prog *p)
 
437
{
 
438
        Prog *next;
 
439
 
 
440
        p->as = AMOVL;
 
441
        p->from.type = D_INDIR+D_TLS;
 
442
        p->from.offset = 0;
 
443
        p->to.type = D_CX;
 
444
 
 
445
        next = p->link;
 
446
        progedit(ctxt, p);
 
447
        while(p->link != next)
 
448
                p = p->link;
 
449
        
 
450
        if(p->from.index == D_TLS)
 
451
                p->from.scale = 2;
 
452
 
 
453
        return p;
 
454
}
 
455
 
 
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.
 
462
static Prog*
 
463
stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
 
464
{
 
465
        Prog *q, *q1;
 
466
        int arg;
 
467
 
 
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);
 
475
                p->as = ACMPL;
 
476
                p->from.type = D_INDIR+D_CX;
 
477
                p->from.offset = 4;
 
478
                p->to.type = D_SP;
 
479
 
 
480
                p = appendp(ctxt, p);
 
481
                p->as = AJCC;
 
482
                p->to.type = D_BRANCH;
 
483
                p->to.offset = 4;
 
484
                q1 = p;
 
485
 
 
486
                p = appendp(ctxt, p);
 
487
                p->as = AINT;
 
488
                p->from.type = D_CONST;
 
489
                p->from.offset = 3;
 
490
                
 
491
                p = appendp(ctxt, p);
 
492
                p->as = ANOP;
 
493
                q1->pcond = p;
 
494
        }
 
495
        q1 = nil;
 
496
 
 
497
        if(framesize <= StackSmall) {
 
498
                // small stack: SP <= stackguard
 
499
                //      CMPL SP, stackguard
 
500
                p = appendp(ctxt, p);
 
501
                p->as = ACMPL;
 
502
                p->from.type = D_SP;
 
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);
 
509
                p->as = ALEAL;
 
510
                p->from.type = D_INDIR+D_SP;
 
511
                p->from.offset = -(framesize-StackSmall);
 
512
                p->to.type = D_AX;
 
513
 
 
514
                p = appendp(ctxt, p);
 
515
                p->as = ACMPL;
 
516
                p->from.type = D_AX;
 
517
                p->to.type = D_INDIR+D_CX;
 
518
        } else {
 
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.
 
524
                //
 
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);
 
534
                p->as = AMOVL;
 
535
                p->from.type = D_INDIR+D_CX;
 
536
                p->from.offset = 0;
 
537
                p->to.type = D_SI;
 
538
 
 
539
                p = appendp(ctxt, p);
 
540
                p->as = ACMPL;
 
541
                p->from.type = D_SI;
 
542
                p->to.type = D_CONST;
 
543
                p->to.offset = (uint32)StackPreempt;
 
544
 
 
545
                p = appendp(ctxt, p);
 
546
                p->as = AJEQ;
 
547
                p->to.type = D_BRANCH;
 
548
                q1 = p;
 
549
 
 
550
                p = appendp(ctxt, p);
 
551
                p->as = ALEAL;
 
552
                p->from.type = D_INDIR+D_SP;
 
553
                p->from.offset = StackGuard;
 
554
                p->to.type = D_AX;
 
555
                
 
556
                p = appendp(ctxt, p);
 
557
                p->as = ASUBL;
 
558
                p->from.type = D_SI;
 
559
                p->from.offset = 0;
 
560
                p->to.type = D_AX;
 
561
                
 
562
                p = appendp(ctxt, p);
 
563
                p->as = ACMPL;
 
564
                p->from.type = D_AX;
 
565
                p->to.type = D_CONST;
 
566
                p->to.offset = framesize+(StackGuard-StackSmall);
 
567
        }               
 
568
                        
 
569
        // common
 
570
        p = appendp(ctxt, p);
 
571
        p->as = AJHI;
 
572
        p->to.type = D_BRANCH;
 
573
        p->to.offset = 4;
 
574
        q = p;
 
575
 
 
576
        p = appendp(ctxt, p);   // save frame size in DI
 
577
        p->as = AMOVL;
 
578
        p->to.type = D_DI;
 
579
        p->from.type = D_CONST;
 
580
 
 
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
 
588
        // instructions.
 
589
        if(StackTop + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
 
590
                p->from.offset = (framesize+7) & ~7LL;
 
591
 
 
592
        arg = ctxt->cursym->text->to.offset2;
 
593
        if(arg == 1) // special marker for known 0
 
594
                arg = 0;
 
595
        if(arg&3)
 
596
                ctxt->diag("misaligned argument size in stack split");
 
597
        p = appendp(ctxt, p);   // save arg size in AX
 
598
        p->as = AMOVL;
 
599
        p->to.type = D_AX;
 
600
        p->from.type = D_CONST;
 
601
        p->from.offset = arg;
 
602
 
 
603
        p = appendp(ctxt, p);
 
604
        p->as = ACALL;
 
605
        p->to.type = D_BRANCH;
 
606
        p->to.sym = ctxt->symmorestack[noctxt];
 
607
 
 
608
        p = appendp(ctxt, p);
 
609
        p->as = AJMP;
 
610
        p->to.type = D_BRANCH;
 
611
        p->pcond = ctxt->cursym->text->link;
 
612
 
 
613
        if(q != nil)
 
614
                q->pcond = p->link;
 
615
        if(q1 != nil)
 
616
                q1->pcond = q->link;
 
617
        
 
618
        *jmpok = q;
 
619
        return p;
 
620
}
 
621
 
 
622
static void xfol(Link*, Prog*, Prog**);
 
623
 
 
624
static void
 
625
follow(Link *ctxt, LSym *s)
 
626
{
 
627
        Prog *firstp, *lastp;
 
628
 
 
629
        ctxt->cursym = s;
 
630
 
 
631
        firstp = ctxt->arch->prg();
 
632
        lastp = firstp;
 
633
        xfol(ctxt, s->text, &lastp);
 
634
        lastp->link = nil;
 
635
        s->text = firstp->link;
 
636
}
 
637
 
 
638
static int
 
639
nofollow(int a)
 
640
{
 
641
        switch(a) {
 
642
        case AJMP:
 
643
        case ARET:
 
644
        case AIRETL:
 
645
        case AIRETW:
 
646
        case AUNDEF:
 
647
                return 1;
 
648
        }
 
649
        return 0;
 
650
}
 
651
 
 
652
static int
 
653
pushpop(int a)
 
654
{
 
655
        switch(a) {
 
656
        case APUSHL:
 
657
        case APUSHFL:
 
658
        case APUSHW:
 
659
        case APUSHFW:
 
660
        case APOPL:
 
661
        case APOPFL:
 
662
        case APOPW:
 
663
        case APOPFW:
 
664
                return 1;
 
665
        }
 
666
        return 0;
 
667
}
 
668
 
 
669
static int
 
670
relinv(int a)
 
671
{
 
672
 
 
673
        switch(a) {
 
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;
 
690
        }
 
691
        sysfatal("unknown relation: %s", anames8[a]);
 
692
        return 0;
 
693
}
 
694
 
 
695
static void
 
696
xfol(Link *ctxt, Prog *p, Prog **last)
 
697
{
 
698
        Prog *q;
 
699
        int i;
 
700
        enum as a;
 
701
 
 
702
loop:
 
703
        if(p == nil)
 
704
                return;
 
705
        if(p->as == AJMP)
 
706
        if((q = p->pcond) != nil && q->as != ATEXT) {
 
707
                /* mark instruction as done and continue layout at target of jump */
 
708
                p->mark = 1;
 
709
                p = q;
 
710
                if(p->mark == 0)
 
711
                        goto loop;
 
712
        }
 
713
        if(p->mark) {
 
714
                /* 
 
715
                 * p goes here, but already used it elsewhere.
 
716
                 * copy up to 4 instructions or else branch to other copy.
 
717
                 */
 
718
                for(i=0,q=p; i<4; i++,q=q->link) {
 
719
                        if(q == nil)
 
720
                                break;
 
721
                        if(q == *last)
 
722
                                break;
 
723
                        a = q->as;
 
724
                        if(a == ANOP) {
 
725
                                i--;
 
726
                                continue;
 
727
                        }
 
728
                        if(nofollow(a) || pushpop(a))   
 
729
                                break;  // NOTE(rsc): arm does goto copy
 
730
                        if(q->pcond == nil || q->pcond->mark)
 
731
                                continue;
 
732
                        if(a == ACALL || a == ALOOP)
 
733
                                continue;
 
734
                        for(;;) {
 
735
                                if(p->as == ANOP) {
 
736
                                        p = p->link;
 
737
                                        continue;
 
738
                                }
 
739
                                q = copyp(ctxt, p);
 
740
                                p = p->link;
 
741
                                q->mark = 1;
 
742
                                (*last)->link = q;
 
743
                                *last = q;
 
744
                                if(q->as != a || q->pcond == nil || q->pcond->mark)
 
745
                                        continue;
 
746
 
 
747
                                q->as = relinv(q->as);
 
748
                                p = q->pcond;
 
749
                                q->pcond = q->link;
 
750
                                q->link = p;
 
751
                                xfol(ctxt, q->link, last);
 
752
                                p = q->link;
 
753
                                if(p->mark)
 
754
                                        return;
 
755
                                goto loop;
 
756
                        }
 
757
                } /* */
 
758
                q = ctxt->arch->prg();
 
759
                q->as = AJMP;
 
760
                q->lineno = p->lineno;
 
761
                q->to.type = D_BRANCH;
 
762
                q->to.offset = p->pc;
 
763
                q->pcond = p;
 
764
                p = q;
 
765
        }
 
766
        
 
767
        /* emit p */
 
768
        p->mark = 1;
 
769
        (*last)->link = p;
 
770
        *last = p;
 
771
        a = p->as;
 
772
 
 
773
        /* continue loop with what comes after p */
 
774
        if(nofollow(a))
 
775
                return;
 
776
        if(p->pcond != nil && a != ACALL) {
 
777
                /*
 
778
                 * some kind of conditional branch.
 
779
                 * recurse to follow one path.
 
780
                 * continue loop on the other.
 
781
                 */
 
782
                if((q = brchain(ctxt, p->pcond)) != nil)
 
783
                        p->pcond = q;
 
784
                if((q = brchain(ctxt, p->link)) != nil)
 
785
                        p->link = q;
 
786
                if(p->from.type == D_CONST) {
 
787
                        if(p->from.offset == 1) {
 
788
                                /*
 
789
                                 * expect conditional jump to be taken.
 
790
                                 * rewrite so that's the fall-through case.
 
791
                                 */
 
792
                                p->as = relinv(a);
 
793
                                q = p->link;
 
794
                                p->link = p->pcond;
 
795
                                p->pcond = q;
 
796
                        }
 
797
                } else {
 
798
                        q = p->link;
 
799
                        if(q->mark)
 
800
                        if(a != ALOOP) {
 
801
                                p->as = relinv(a);
 
802
                                p->link = p->pcond;
 
803
                                p->pcond = q;
 
804
                        }
 
805
                }
 
806
                xfol(ctxt, p->link, last);
 
807
                if(p->pcond->mark)
 
808
                        return;
 
809
                p = p->pcond;
 
810
                goto loop;
 
811
        }
 
812
        p = p->link;
 
813
        goto loop;
 
814
}
 
815
 
 
816
LinkArch link386 = {
 
817
        .name = "386",
 
818
        .thechar = '8',
 
819
 
 
820
        .addstacksplit = addstacksplit,
 
821
        .assemble = span8,
 
822
        .datasize = datasize,
 
823
        .follow = follow,
 
824
        .iscall = iscall,
 
825
        .isdata = isdata,
 
826
        .prg = prg,
 
827
        .progedit = progedit,
 
828
        .settextflag = settextflag,
 
829
        .symtype = symtype,
 
830
        .textflag = textflag,
 
831
 
 
832
        .minlc = 1,
 
833
        .ptrsize = 4,
 
834
        .regsize = 4,
 
835
 
 
836
        .D_ADDR = D_ADDR,
 
837
        .D_AUTO = D_AUTO,
 
838
        .D_BRANCH = D_BRANCH,
 
839
        .D_CONST = D_CONST,
 
840
        .D_EXTERN = D_EXTERN,
 
841
        .D_FCONST = D_FCONST,
 
842
        .D_NONE = D_NONE,
 
843
        .D_PARAM = D_PARAM,
 
844
        .D_SCONST = D_SCONST,
 
845
        .D_STATIC = D_STATIC,
 
846
 
 
847
        .ACALL = ACALL,
 
848
        .ADATA = ADATA,
 
849
        .AEND = AEND,
 
850
        .AFUNCDATA = AFUNCDATA,
 
851
        .AGLOBL = AGLOBL,
 
852
        .AJMP = AJMP,
 
853
        .ANOP = ANOP,
 
854
        .APCDATA = APCDATA,
 
855
        .ARET = ARET,
 
856
        .ATEXT = ATEXT,
 
857
        .ATYPE = ATYPE,
 
858
        .AUSEFIELD = AUSEFIELD,
 
859
};