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

« back to all changes in this revision

Viewing changes to src/liblink/obj5.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
// Derived from Inferno utils/5c/swt.c
 
2
// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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/5l/5.out.h"
 
36
#include "../pkg/runtime/stack.h"
 
37
 
 
38
static Prog zprg = {
 
39
        .as = AGOK,
 
40
        .scond = C_SCOND_NONE,
 
41
        .reg = NREG,
 
42
        .from = {
 
43
                .name = D_NONE,
 
44
                .type = D_NONE,
 
45
                .reg = NREG,
 
46
        },
 
47
        .to = {
 
48
                .name = D_NONE,
 
49
                .type = D_NONE,
 
50
                .reg = NREG,
 
51
        },
 
52
};
 
53
 
 
54
static int
 
55
symtype(Addr *a)
 
56
{
 
57
        return a->name;
 
58
}
 
59
 
 
60
static int
 
61
isdata(Prog *p)
 
62
{
 
63
        return p->as == ADATA || p->as == AGLOBL;
 
64
}
 
65
 
 
66
static int
 
67
iscall(Prog *p)
 
68
{
 
69
        return p->as == ABL;
 
70
}
 
71
 
 
72
static int
 
73
datasize(Prog *p)
 
74
{
 
75
        return p->reg;
 
76
}
 
77
 
 
78
static int
 
79
textflag(Prog *p)
 
80
{
 
81
        return p->reg;
 
82
}
 
83
 
 
84
static void
 
85
settextflag(Prog *p, int f)
 
86
{
 
87
        p->reg = f;
 
88
}
 
89
 
 
90
static void
 
91
progedit(Link *ctxt, Prog *p)
 
92
{
 
93
        char literal[64];
 
94
        LSym *s;
 
95
        LSym *tlsfallback;
 
96
 
 
97
        p->from.class = 0;
 
98
        p->to.class = 0;
 
99
 
 
100
        // Rewrite B/BL to symbol as D_BRANCH.
 
101
        switch(p->as) {
 
102
        case AB:
 
103
        case ABL:
 
104
        case ADUFFZERO:
 
105
        case ADUFFCOPY:
 
106
                if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
 
107
                        p->to.type = D_BRANCH;
 
108
                break;
 
109
        }
 
110
 
 
111
        // Replace TLS register fetches on older ARM procesors.
 
112
        switch(p->as) {
 
113
        case AMRC:
 
114
                // If the instruction matches MRC 15, 0, <reg>, C13, C0, 3, replace it.
 
115
                if(ctxt->goarm < 7 && (p->to.offset & 0xffff0fff) == 0xee1d0f70) {
 
116
                        tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
 
117
 
 
118
                        // BL runtime.read_tls_fallback(SB)
 
119
                        p->as = ABL;
 
120
                        p->to.type = D_BRANCH;
 
121
                        p->to.sym = tlsfallback;
 
122
                        p->to.offset = 0;
 
123
                } else {
 
124
                        // Otherwise, MRC/MCR instructions need no further treatment.
 
125
                        p->as = AWORD;
 
126
                }
 
127
                break;
 
128
        }
 
129
 
 
130
        // Rewrite float constants to values stored in memory.
 
131
        switch(p->as) {
 
132
        case AMOVF:
 
133
                if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
 
134
                   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
 
135
                        int32 i32;
 
136
                        float32 f32;
 
137
                        f32 = p->from.u.dval;
 
138
                        memmove(&i32, &f32, 4);
 
139
                        sprint(literal, "$f32.%08ux", (uint32)i32);
 
140
                        s = linklookup(ctxt, literal, 0);
 
141
                        if(s->type == 0) {
 
142
                                s->type = SRODATA;
 
143
                                adduint32(ctxt, s, i32);
 
144
                                s->reachable = 0;
 
145
                        }
 
146
                        p->from.type = D_OREG;
 
147
                        p->from.sym = s;
 
148
                        p->from.name = D_EXTERN;
 
149
                        p->from.offset = 0;
 
150
                }
 
151
                break;
 
152
 
 
153
        case AMOVD:
 
154
                if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
 
155
                   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
 
156
                        int64 i64;
 
157
                        memmove(&i64, &p->from.u.dval, 8);
 
158
                        sprint(literal, "$f64.%016llux", (uvlong)i64);
 
159
                        s = linklookup(ctxt, literal, 0);
 
160
                        if(s->type == 0) {
 
161
                                s->type = SRODATA;
 
162
                                adduint64(ctxt, s, i64);
 
163
                                s->reachable = 0;
 
164
                        }
 
165
                        p->from.type = D_OREG;
 
166
                        p->from.sym = s;
 
167
                        p->from.name = D_EXTERN;
 
168
                        p->from.offset = 0;
 
169
                }
 
170
                break;
 
171
        }
 
172
 
 
173
        if(ctxt->flag_shared) {
 
174
                // Shared libraries use R_ARM_TLS_IE32 instead of 
 
175
                // R_ARM_TLS_LE32, replacing the link time constant TLS offset in
 
176
                // runtime.tlsgm with an address to a GOT entry containing the 
 
177
                // offset. Rewrite $runtime.tlsgm(SB) to runtime.tlsgm(SB) to
 
178
                // compensate.
 
179
                if(ctxt->gmsym == nil)
 
180
                        ctxt->gmsym = linklookup(ctxt, "runtime.tlsgm", 0);
 
181
 
 
182
                if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->gmsym)
 
183
                        p->from.type = D_OREG;
 
184
                if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->gmsym)
 
185
                        p->to.type = D_OREG;
 
186
        }
 
187
}
 
188
 
 
189
static Prog*
 
190
prg(void)
 
191
{
 
192
        Prog *p;
 
193
 
 
194
        p = emallocz(sizeof(*p));
 
195
        *p = zprg;
 
196
        return p;
 
197
}
 
198
 
 
199
static  Prog*   stacksplit(Link*, Prog*, int32, int);
 
200
static  void            initdiv(Link*);
 
201
static  void    softfloat(Link*, LSym*);
 
202
 
 
203
// Prog.mark
 
204
enum
 
205
{
 
206
        FOLL = 1<<0,
 
207
        LABEL = 1<<1,
 
208
        LEAF = 1<<2,
 
209
};
 
210
 
 
211
static void
 
212
linkcase(Prog *casep)
 
213
{
 
214
        Prog *p;
 
215
 
 
216
        for(p = casep; p != nil; p = p->link){
 
217
                if(p->as == ABCASE) {
 
218
                        for(; p != nil && p->as == ABCASE; p = p->link)
 
219
                                p->pcrel = casep;
 
220
                        break;
 
221
                }
 
222
        }
 
223
}
 
224
 
 
225
static void
 
226
nocache(Prog *p)
 
227
{
 
228
        p->optab = 0;
 
229
        p->from.class = 0;
 
230
        p->to.class = 0;
 
231
}
 
232
 
 
233
static void
 
234
addstacksplit(Link *ctxt, LSym *cursym)
 
235
{
 
236
        Prog *p, *pl, *q, *q1, *q2;
 
237
        int o;
 
238
        int32 autosize, autoffset;
 
239
        
 
240
        autosize = 0;
 
241
 
 
242
        if(ctxt->symmorestack[0] == nil) {
 
243
                ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
 
244
                ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
 
245
        }
 
246
 
 
247
        q = nil;
 
248
        
 
249
        ctxt->cursym = cursym;
 
250
 
 
251
        if(cursym->text == nil || cursym->text->link == nil)
 
252
                return;                         
 
253
 
 
254
        softfloat(ctxt, cursym);
 
255
 
 
256
        p = cursym->text;
 
257
        autoffset = p->to.offset;
 
258
        if(autoffset < 0)
 
259
                autoffset = 0;
 
260
        cursym->locals = autoffset;
 
261
        cursym->args = p->to.offset2;
 
262
 
 
263
        if(ctxt->debugzerostack) {
 
264
                if(autoffset && !(p->reg&NOSPLIT)) {
 
265
                        // MOVW $4(R13), R1
 
266
                        p = appendp(ctxt, p);
 
267
                        p->as = AMOVW;
 
268
                        p->from.type = D_CONST;
 
269
                        p->from.reg = 13;
 
270
                        p->from.offset = 4;
 
271
                        p->to.type = D_REG;
 
272
                        p->to.reg = 1;
 
273
        
 
274
                        // MOVW $n(R13), R2
 
275
                        p = appendp(ctxt, p);
 
276
                        p->as = AMOVW;
 
277
                        p->from.type = D_CONST;
 
278
                        p->from.reg = 13;
 
279
                        p->from.offset = 4 + autoffset;
 
280
                        p->to.type = D_REG;
 
281
                        p->to.reg = 2;
 
282
        
 
283
                        // MOVW $0, R3
 
284
                        p = appendp(ctxt, p);
 
285
                        p->as = AMOVW;
 
286
                        p->from.type = D_CONST;
 
287
                        p->from.offset = 0;
 
288
                        p->to.type = D_REG;
 
289
                        p->to.reg = 3;
 
290
        
 
291
                        // L:
 
292
                        //      MOVW.nil R3, 0(R1) +4
 
293
                        //      CMP R1, R2
 
294
                        //      BNE L
 
295
                        p = pl = appendp(ctxt, p);
 
296
                        p->as = AMOVW;
 
297
                        p->from.type = D_REG;
 
298
                        p->from.reg = 3;
 
299
                        p->to.type = D_OREG;
 
300
                        p->to.reg = 1;
 
301
                        p->to.offset = 4;
 
302
                        p->scond |= C_PBIT;
 
303
        
 
304
                        p = appendp(ctxt, p);
 
305
                        p->as = ACMP;
 
306
                        p->from.type = D_REG;
 
307
                        p->from.reg = 1;
 
308
                        p->reg = 2;
 
309
        
 
310
                        p = appendp(ctxt, p);
 
311
                        p->as = ABNE;
 
312
                        p->to.type = D_BRANCH;
 
313
                        p->pcond = pl;
 
314
                }
 
315
        }
 
316
 
 
317
        /*
 
318
         * find leaf subroutines
 
319
         * strip NOPs
 
320
         * expand RET
 
321
         * expand BECOME pseudo
 
322
         */
 
323
 
 
324
        for(p = cursym->text; p != nil; p = p->link) {
 
325
                switch(p->as) {
 
326
                case ACASE:
 
327
                        if(ctxt->flag_shared)
 
328
                                linkcase(p);
 
329
                        break;
 
330
 
 
331
                case ATEXT:
 
332
                        p->mark |= LEAF;
 
333
                        break;
 
334
 
 
335
                case ARET:
 
336
                        break;
 
337
 
 
338
                case ADIV:
 
339
                case ADIVU:
 
340
                case AMOD:
 
341
                case AMODU:
 
342
                        q = p;
 
343
                        if(ctxt->sym_div == nil)
 
344
                                initdiv(ctxt);
 
345
                        cursym->text->mark &= ~LEAF;
 
346
                        continue;
 
347
 
 
348
                case ANOP:
 
349
                        q1 = p->link;
 
350
                        q->link = q1;           /* q is non-nop */
 
351
                        if(q1 != nil)
 
352
                                q1->mark |= p->mark;
 
353
                        continue;
 
354
 
 
355
                case ABL:
 
356
                case ABX:
 
357
                case ADUFFZERO:
 
358
                case ADUFFCOPY:
 
359
                        cursym->text->mark &= ~LEAF;
 
360
 
 
361
                case ABCASE:
 
362
                case AB:
 
363
 
 
364
                case ABEQ:
 
365
                case ABNE:
 
366
                case ABCS:
 
367
                case ABHS:
 
368
                case ABCC:
 
369
                case ABLO:
 
370
                case ABMI:
 
371
                case ABPL:
 
372
                case ABVS:
 
373
                case ABVC:
 
374
                case ABHI:
 
375
                case ABLS:
 
376
                case ABGE:
 
377
                case ABLT:
 
378
                case ABGT:
 
379
                case ABLE:
 
380
                        q1 = p->pcond;
 
381
                        if(q1 != nil) {
 
382
                                while(q1->as == ANOP) {
 
383
                                        q1 = q1->link;
 
384
                                        p->pcond = q1;
 
385
                                }
 
386
                        }
 
387
                        break;
 
388
                }
 
389
                q = p;
 
390
        }
 
391
 
 
392
        for(p = cursym->text; p != nil; p = p->link) {
 
393
                o = p->as;
 
394
                switch(o) {
 
395
                case ATEXT:
 
396
                        autosize = p->to.offset + 4;
 
397
                        if(autosize <= 4)
 
398
                        if(cursym->text->mark & LEAF) {
 
399
                                p->to.offset = -4;
 
400
                                autosize = 0;
 
401
                        }
 
402
 
 
403
                        if(!autosize && !(cursym->text->mark & LEAF)) {
 
404
                                if(ctxt->debugvlog) {
 
405
                                        Bprint(ctxt->bso, "save suppressed in: %s\n",
 
406
                                                cursym->name);
 
407
                                        Bflush(ctxt->bso);
 
408
                                }
 
409
                                cursym->text->mark |= LEAF;
 
410
                        }
 
411
                        if(cursym->text->mark & LEAF) {
 
412
                                cursym->leaf = 1;
 
413
                                if(!autosize)
 
414
                                        break;
 
415
                        }
 
416
 
 
417
                        if(!(p->reg & NOSPLIT))
 
418
                                p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
 
419
                        
 
420
                        // MOVW.W               R14,$-autosize(SP)
 
421
                        p = appendp(ctxt, p);
 
422
                        p->as = AMOVW;
 
423
                        p->scond |= C_WBIT;
 
424
                        p->from.type = D_REG;
 
425
                        p->from.reg = REGLINK;
 
426
                        p->to.type = D_OREG;
 
427
                        p->to.offset = -autosize;
 
428
                        p->to.reg = REGSP;
 
429
                        p->spadj = autosize;
 
430
                        
 
431
                        if(cursym->text->reg & WRAPPER) {
 
432
                                // g->panicwrap += autosize;
 
433
                                // MOVW panicwrap_offset(g), R3
 
434
                                // ADD $autosize, R3
 
435
                                // MOVW R3 panicwrap_offset(g)
 
436
                                p = appendp(ctxt, p);
 
437
                                p->as = AMOVW;
 
438
                                p->from.type = D_OREG;
 
439
                                p->from.reg = REGG;
 
440
                                p->from.offset = 2*ctxt->arch->ptrsize;
 
441
                                p->to.type = D_REG;
 
442
                                p->to.reg = 3;
 
443
                        
 
444
                                p = appendp(ctxt, p);
 
445
                                p->as = AADD;
 
446
                                p->from.type = D_CONST;
 
447
                                p->from.offset = autosize;
 
448
                                p->to.type = D_REG;
 
449
                                p->to.reg = 3;
 
450
                                
 
451
                                p = appendp(ctxt, p);
 
452
                                p->as = AMOVW;
 
453
                                p->from.type = D_REG;
 
454
                                p->from.reg = 3;
 
455
                                p->to.type = D_OREG;
 
456
                                p->to.reg = REGG;
 
457
                                p->to.offset = 2*ctxt->arch->ptrsize;
 
458
                        }
 
459
                        break;
 
460
 
 
461
                case ARET:
 
462
                        nocache(p);
 
463
                        if(cursym->text->mark & LEAF) {
 
464
                                if(!autosize) {
 
465
                                        p->as = AB;
 
466
                                        p->from = zprg.from;
 
467
                                        if(p->to.sym) { // retjmp
 
468
                                                p->to.type = D_BRANCH;
 
469
                                        } else {
 
470
                                                p->to.type = D_OREG;
 
471
                                                p->to.offset = 0;
 
472
                                                p->to.reg = REGLINK;
 
473
                                        }
 
474
                                        break;
 
475
                                }
 
476
                        }
 
477
 
 
478
                        if(cursym->text->reg & WRAPPER) {
 
479
                                int scond;
 
480
                                
 
481
                                // Preserve original RET's cond, to allow RET.EQ
 
482
                                // in the implementation of reflect.call.
 
483
                                scond = p->scond;
 
484
                                p->scond = C_SCOND_NONE;
 
485
 
 
486
                                // g->panicwrap -= autosize;
 
487
                                // MOVW panicwrap_offset(g), R3
 
488
                                // SUB $autosize, R3
 
489
                                // MOVW R3 panicwrap_offset(g)
 
490
                                p->as = AMOVW;
 
491
                                p->from.type = D_OREG;
 
492
                                p->from.reg = REGG;
 
493
                                p->from.offset = 2*ctxt->arch->ptrsize;
 
494
                                p->to.type = D_REG;
 
495
                                p->to.reg = 3;
 
496
                                p = appendp(ctxt, p);
 
497
                        
 
498
                                p->as = ASUB;
 
499
                                p->from.type = D_CONST;
 
500
                                p->from.offset = autosize;
 
501
                                p->to.type = D_REG;
 
502
                                p->to.reg = 3;
 
503
                                p = appendp(ctxt, p);
 
504
 
 
505
                                p->as = AMOVW;
 
506
                                p->from.type = D_REG;
 
507
                                p->from.reg = 3;
 
508
                                p->to.type = D_OREG;
 
509
                                p->to.reg = REGG;
 
510
                                p->to.offset = 2*ctxt->arch->ptrsize;
 
511
                                p = appendp(ctxt, p);
 
512
 
 
513
                                p->scond = scond;
 
514
                        }
 
515
 
 
516
                        p->as = AMOVW;
 
517
                        p->scond |= C_PBIT;
 
518
                        p->from.type = D_OREG;
 
519
                        p->from.offset = autosize;
 
520
                        p->from.reg = REGSP;
 
521
                        p->to.type = D_REG;
 
522
                        p->to.reg = REGPC;
 
523
                        // If there are instructions following
 
524
                        // this ARET, they come from a branch
 
525
                        // with the same stackframe, so no spadj.
 
526
                        
 
527
                        if(p->to.sym) { // retjmp
 
528
                                p->to.reg = REGLINK;
 
529
                                q2 = appendp(ctxt, p);
 
530
                                q2->as = AB;
 
531
                                q2->to.type = D_BRANCH;
 
532
                                q2->to.sym = p->to.sym;
 
533
                                p->to.sym = nil;
 
534
                                p = q2;
 
535
                        }
 
536
                        break;
 
537
 
 
538
                case AADD:
 
539
                        if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
 
540
                                p->spadj = -p->from.offset;
 
541
                        break;
 
542
 
 
543
                case ASUB:
 
544
                        if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
 
545
                                p->spadj = p->from.offset;
 
546
                        break;
 
547
 
 
548
                case ADIV:
 
549
                case ADIVU:
 
550
                case AMOD:
 
551
                case AMODU:
 
552
                        if(ctxt->debugdivmod)
 
553
                                break;
 
554
                        if(p->from.type != D_REG)
 
555
                                break;
 
556
                        if(p->to.type != D_REG)
 
557
                                break;
 
558
                        q1 = p;
 
559
 
 
560
                        /* MOV a,4(SP) */
 
561
                        p = appendp(ctxt, p);
 
562
                        p->as = AMOVW;
 
563
                        p->lineno = q1->lineno;
 
564
                        p->from.type = D_REG;
 
565
                        p->from.reg = q1->from.reg;
 
566
                        p->to.type = D_OREG;
 
567
                        p->to.reg = REGSP;
 
568
                        p->to.offset = 4;
 
569
 
 
570
                        /* MOV b,REGTMP */
 
571
                        p = appendp(ctxt, p);
 
572
                        p->as = AMOVW;
 
573
                        p->lineno = q1->lineno;
 
574
                        p->from.type = D_REG;
 
575
                        p->from.reg = q1->reg;
 
576
                        if(q1->reg == NREG)
 
577
                                p->from.reg = q1->to.reg;
 
578
                        p->to.type = D_REG;
 
579
                        p->to.reg = REGTMP;
 
580
                        p->to.offset = 0;
 
581
 
 
582
                        /* CALL appropriate */
 
583
                        p = appendp(ctxt, p);
 
584
                        p->as = ABL;
 
585
                        p->lineno = q1->lineno;
 
586
                        p->to.type = D_BRANCH;
 
587
                        switch(o) {
 
588
                        case ADIV:
 
589
                                p->to.sym = ctxt->sym_div;
 
590
                                break;
 
591
                        case ADIVU:
 
592
                                p->to.sym = ctxt->sym_divu;
 
593
                                break;
 
594
                        case AMOD:
 
595
                                p->to.sym = ctxt->sym_mod;
 
596
                                break;
 
597
                        case AMODU:
 
598
                                p->to.sym = ctxt->sym_modu;
 
599
                                break;
 
600
                        }
 
601
 
 
602
                        /* MOV REGTMP, b */
 
603
                        p = appendp(ctxt, p);
 
604
                        p->as = AMOVW;
 
605
                        p->lineno = q1->lineno;
 
606
                        p->from.type = D_REG;
 
607
                        p->from.reg = REGTMP;
 
608
                        p->from.offset = 0;
 
609
                        p->to.type = D_REG;
 
610
                        p->to.reg = q1->to.reg;
 
611
 
 
612
                        /* ADD $8,SP */
 
613
                        p = appendp(ctxt, p);
 
614
                        p->as = AADD;
 
615
                        p->lineno = q1->lineno;
 
616
                        p->from.type = D_CONST;
 
617
                        p->from.reg = NREG;
 
618
                        p->from.offset = 8;
 
619
                        p->reg = NREG;
 
620
                        p->to.type = D_REG;
 
621
                        p->to.reg = REGSP;
 
622
                        p->spadj = -8;
 
623
 
 
624
                        /* Keep saved LR at 0(SP) after SP change. */
 
625
                        /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
 
626
                        /* TODO: Remove SP adjustments; see issue 6699. */
 
627
                        q1->as = AMOVW;
 
628
                        q1->from.type = D_OREG;
 
629
                        q1->from.reg = REGSP;
 
630
                        q1->from.offset = 0;
 
631
                        q1->reg = NREG;
 
632
                        q1->to.type = D_REG;
 
633
                        q1->to.reg = REGTMP;
 
634
 
 
635
                        /* SUB $8,SP */
 
636
                        q1 = appendp(ctxt, q1);
 
637
                        q1->as = AMOVW;
 
638
                        q1->from.type = D_REG;
 
639
                        q1->from.reg = REGTMP;
 
640
                        q1->reg = NREG;
 
641
                        q1->to.type = D_OREG;
 
642
                        q1->to.reg = REGSP;
 
643
                        q1->to.offset = -8;
 
644
                        q1->scond |= C_WBIT;
 
645
                        q1->spadj = 8;
 
646
 
 
647
                        break;
 
648
                case AMOVW:
 
649
                        if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
 
650
                                p->spadj = -p->to.offset;
 
651
                        if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
 
652
                                p->spadj = -p->from.offset;
 
653
                        if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
 
654
                                p->spadj = -p->from.offset;
 
655
                        break;
 
656
                }
 
657
        }
 
658
}
 
659
 
 
660
static void
 
661
softfloat(Link *ctxt, LSym *cursym)
 
662
{
 
663
        Prog *p, *next;
 
664
        LSym *symsfloat;
 
665
        int wasfloat;
 
666
 
 
667
        if(ctxt->goarm > 5)
 
668
                return;
 
669
 
 
670
        symsfloat = linklookup(ctxt, "_sfloat", 0);
 
671
 
 
672
        wasfloat = 0;
 
673
        for(p = cursym->text; p != nil; p = p->link)
 
674
                if(p->pcond != nil)
 
675
                        p->pcond->mark |= LABEL;
 
676
        for(p = cursym->text; p != nil; p = p->link) {
 
677
                switch(p->as) {
 
678
                case AMOVW:
 
679
                        if(p->to.type == D_FREG || p->from.type == D_FREG)
 
680
                                goto soft;
 
681
                        goto notsoft;
 
682
 
 
683
                case AMOVWD:
 
684
                case AMOVWF:
 
685
                case AMOVDW:
 
686
                case AMOVFW:
 
687
                case AMOVFD:
 
688
                case AMOVDF:
 
689
                case AMOVF:
 
690
                case AMOVD:
 
691
 
 
692
                case ACMPF:
 
693
                case ACMPD:
 
694
                case AADDF:
 
695
                case AADDD:
 
696
                case ASUBF:
 
697
                case ASUBD:
 
698
                case AMULF:
 
699
                case AMULD:
 
700
                case ADIVF:
 
701
                case ADIVD:
 
702
                case ASQRTF:
 
703
                case ASQRTD:
 
704
                case AABSF:
 
705
                case AABSD:
 
706
                        goto soft;
 
707
 
 
708
                default:
 
709
                        goto notsoft;
 
710
 
 
711
                soft:
 
712
                        if (!wasfloat || (p->mark&LABEL)) {
 
713
                                next = ctxt->arch->prg();
 
714
                                *next = *p;
 
715
 
 
716
                                // BL _sfloat(SB)
 
717
                                *p = zprg;
 
718
                                p->link = next;
 
719
                                p->as = ABL;
 
720
                                p->to.type = D_BRANCH;
 
721
                                p->to.sym = symsfloat;
 
722
                                p->lineno = next->lineno;
 
723
 
 
724
                                p = next;
 
725
                                wasfloat = 1;
 
726
                        }
 
727
                        break;
 
728
 
 
729
                notsoft:
 
730
                        wasfloat = 0;
 
731
                }
 
732
        }
 
733
}
 
734
 
 
735
static Prog*
 
736
stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
 
737
{
 
738
        int32 arg;
 
739
 
 
740
        // MOVW                 g_stackguard(g), R1
 
741
        p = appendp(ctxt, p);
 
742
        p->as = AMOVW;
 
743
        p->from.type = D_OREG;
 
744
        p->from.reg = REGG;
 
745
        p->to.type = D_REG;
 
746
        p->to.reg = 1;
 
747
        
 
748
        if(framesize <= StackSmall) {
 
749
                // small stack: SP < stackguard
 
750
                //      CMP     stackguard, SP
 
751
                p = appendp(ctxt, p);
 
752
                p->as = ACMP;
 
753
                p->from.type = D_REG;
 
754
                p->from.reg = 1;
 
755
                p->reg = REGSP;
 
756
        } else if(framesize <= StackBig) {
 
757
                // large stack: SP-framesize < stackguard-StackSmall
 
758
                //      MOVW $-framesize(SP), R2
 
759
                //      CMP stackguard, R2
 
760
                p = appendp(ctxt, p);
 
761
                p->as = AMOVW;
 
762
                p->from.type = D_CONST;
 
763
                p->from.reg = REGSP;
 
764
                p->from.offset = -framesize;
 
765
                p->to.type = D_REG;
 
766
                p->to.reg = 2;
 
767
                
 
768
                p = appendp(ctxt, p);
 
769
                p->as = ACMP;
 
770
                p->from.type = D_REG;
 
771
                p->from.reg = 1;
 
772
                p->reg = 2;
 
773
        } else {
 
774
                // Such a large stack we need to protect against wraparound
 
775
                // if SP is close to zero.
 
776
                //      SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
 
777
                // The +StackGuard on both sides is required to keep the left side positive:
 
778
                // SP is allowed to be slightly below stackguard. See stack.h.
 
779
                //      CMP $StackPreempt, R1
 
780
                //      MOVW.NE $StackGuard(SP), R2
 
781
                //      SUB.NE R1, R2
 
782
                //      MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
 
783
                //      CMP.NE R3, R2
 
784
                p = appendp(ctxt, p);
 
785
                p->as = ACMP;
 
786
                p->from.type = D_CONST;
 
787
                p->from.offset = (uint32)StackPreempt;
 
788
                p->reg = 1;
 
789
 
 
790
                p = appendp(ctxt, p);
 
791
                p->as = AMOVW;
 
792
                p->from.type = D_CONST;
 
793
                p->from.reg = REGSP;
 
794
                p->from.offset = StackGuard;
 
795
                p->to.type = D_REG;
 
796
                p->to.reg = 2;
 
797
                p->scond = C_SCOND_NE;
 
798
                
 
799
                p = appendp(ctxt, p);
 
800
                p->as = ASUB;
 
801
                p->from.type = D_REG;
 
802
                p->from.reg = 1;
 
803
                p->to.type = D_REG;
 
804
                p->to.reg = 2;
 
805
                p->scond = C_SCOND_NE;
 
806
                
 
807
                p = appendp(ctxt, p);
 
808
                p->as = AMOVW;
 
809
                p->from.type = D_CONST;
 
810
                p->from.offset = framesize + (StackGuard - StackSmall);
 
811
                p->to.type = D_REG;
 
812
                p->to.reg = 3;
 
813
                p->scond = C_SCOND_NE;
 
814
                
 
815
                p = appendp(ctxt, p);
 
816
                p->as = ACMP;
 
817
                p->from.type = D_REG;
 
818
                p->from.reg = 3;
 
819
                p->reg = 2;
 
820
                p->scond = C_SCOND_NE;
 
821
        }
 
822
        
 
823
        // MOVW.LS              $framesize, R1
 
824
        p = appendp(ctxt, p);
 
825
        p->as = AMOVW;
 
826
        p->scond = C_SCOND_LS;
 
827
        p->from.type = D_CONST;
 
828
        p->from.offset = framesize;
 
829
        p->to.type = D_REG;
 
830
        p->to.reg = 1;
 
831
 
 
832
        // MOVW.LS              $args, R2
 
833
        p = appendp(ctxt, p);
 
834
        p->as = AMOVW;
 
835
        p->scond = C_SCOND_LS;
 
836
        p->from.type = D_CONST;
 
837
        arg = ctxt->cursym->text->to.offset2;
 
838
        if(arg == 1) // special marker for known 0
 
839
                arg = 0;
 
840
        if(arg&3)
 
841
                ctxt->diag("misaligned argument size in stack split");
 
842
        p->from.offset = arg;
 
843
        p->to.type = D_REG;
 
844
        p->to.reg = 2;
 
845
 
 
846
        // MOVW.LS      R14, R3
 
847
        p = appendp(ctxt, p);
 
848
        p->as = AMOVW;
 
849
        p->scond = C_SCOND_LS;
 
850
        p->from.type = D_REG;
 
851
        p->from.reg = REGLINK;
 
852
        p->to.type = D_REG;
 
853
        p->to.reg = 3;
 
854
 
 
855
        // BL.LS                runtime.morestack(SB) // modifies LR, returns with LO still asserted
 
856
        p = appendp(ctxt, p);
 
857
        p->as = ABL;
 
858
        p->scond = C_SCOND_LS;
 
859
        p->to.type = D_BRANCH;
 
860
        p->to.sym = ctxt->symmorestack[noctxt];
 
861
        
 
862
        // BLS  start
 
863
        p = appendp(ctxt, p);
 
864
        p->as = ABLS;
 
865
        p->to.type = D_BRANCH;
 
866
        p->pcond = ctxt->cursym->text->link;
 
867
        
 
868
        return p;
 
869
}
 
870
 
 
871
static void
 
872
initdiv(Link *ctxt)
 
873
{
 
874
        if(ctxt->sym_div != nil)
 
875
                return;
 
876
        ctxt->sym_div = linklookup(ctxt, "_div", 0);
 
877
        ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
 
878
        ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
 
879
        ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
 
880
}
 
881
 
 
882
static void xfol(Link*, Prog*, Prog**);
 
883
 
 
884
static void
 
885
follow(Link *ctxt, LSym *s)
 
886
{
 
887
        Prog *firstp, *lastp;
 
888
 
 
889
        ctxt->cursym = s;
 
890
 
 
891
        firstp = ctxt->arch->prg();
 
892
        lastp = firstp;
 
893
        xfol(ctxt, s->text, &lastp);
 
894
        lastp->link = nil;
 
895
        s->text = firstp->link;
 
896
}
 
897
 
 
898
static int
 
899
relinv(int a)
 
900
{
 
901
        switch(a) {
 
902
        case ABEQ:      return ABNE;
 
903
        case ABNE:      return ABEQ;
 
904
        case ABCS:      return ABCC;
 
905
        case ABHS:      return ABLO;
 
906
        case ABCC:      return ABCS;
 
907
        case ABLO:      return ABHS;
 
908
        case ABMI:      return ABPL;
 
909
        case ABPL:      return ABMI;
 
910
        case ABVS:      return ABVC;
 
911
        case ABVC:      return ABVS;
 
912
        case ABHI:      return ABLS;
 
913
        case ABLS:      return ABHI;
 
914
        case ABGE:      return ABLT;
 
915
        case ABLT:      return ABGE;
 
916
        case ABGT:      return ABLE;
 
917
        case ABLE:      return ABGT;
 
918
        }
 
919
        sysfatal("unknown relation: %s", anames5[a]);
 
920
        return 0;
 
921
}
 
922
 
 
923
static void
 
924
xfol(Link *ctxt, Prog *p, Prog **last)
 
925
{
 
926
        Prog *q, *r;
 
927
        int a, i;
 
928
 
 
929
loop:
 
930
        if(p == nil)
 
931
                return;
 
932
        a = p->as;
 
933
        if(a == AB) {
 
934
                q = p->pcond;
 
935
                if(q != nil && q->as != ATEXT) {
 
936
                        p->mark |= FOLL;
 
937
                        p = q;
 
938
                        if(!(p->mark & FOLL))
 
939
                                goto loop;
 
940
                }
 
941
        }
 
942
        if(p->mark & FOLL) {
 
943
                for(i=0,q=p; i<4; i++,q=q->link) {
 
944
                        if(q == *last || q == nil)
 
945
                                break;
 
946
                        a = q->as;
 
947
                        if(a == ANOP) {
 
948
                                i--;
 
949
                                continue;
 
950
                        }
 
951
                        if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
 
952
                                goto copy;
 
953
                        if(q->pcond == nil || (q->pcond->mark&FOLL))
 
954
                                continue;
 
955
                        if(a != ABEQ && a != ABNE)
 
956
                                continue;
 
957
                copy:
 
958
                        for(;;) {
 
959
                                r = ctxt->arch->prg();
 
960
                                *r = *p;
 
961
                                if(!(r->mark&FOLL))
 
962
                                        print("can't happen 1\n");
 
963
                                r->mark |= FOLL;
 
964
                                if(p != q) {
 
965
                                        p = p->link;
 
966
                                        (*last)->link = r;
 
967
                                        *last = r;
 
968
                                        continue;
 
969
                                }
 
970
                                (*last)->link = r;
 
971
                                *last = r;
 
972
                                if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
 
973
                                        return;
 
974
                                r->as = ABNE;
 
975
                                if(a == ABNE)
 
976
                                        r->as = ABEQ;
 
977
                                r->pcond = p->link;
 
978
                                r->link = p->pcond;
 
979
                                if(!(r->link->mark&FOLL))
 
980
                                        xfol(ctxt, r->link, last);
 
981
                                if(!(r->pcond->mark&FOLL))
 
982
                                        print("can't happen 2\n");
 
983
                                return;
 
984
                        }
 
985
                }
 
986
                a = AB;
 
987
                q = ctxt->arch->prg();
 
988
                q->as = a;
 
989
                q->lineno = p->lineno;
 
990
                q->to.type = D_BRANCH;
 
991
                q->to.offset = p->pc;
 
992
                q->pcond = p;
 
993
                p = q;
 
994
        }
 
995
        p->mark |= FOLL;
 
996
        (*last)->link = p;
 
997
        *last = p;
 
998
        if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){
 
999
                return;
 
1000
        }
 
1001
        if(p->pcond != nil)
 
1002
        if(a != ABL && a != ABX && p->link != nil) {
 
1003
                q = brchain(ctxt, p->link);
 
1004
                if(a != ATEXT && a != ABCASE)
 
1005
                if(q != nil && (q->mark&FOLL)) {
 
1006
                        p->as = relinv(a);
 
1007
                        p->link = p->pcond;
 
1008
                        p->pcond = q;
 
1009
                }
 
1010
                xfol(ctxt, p->link, last);
 
1011
                q = brchain(ctxt, p->pcond);
 
1012
                if(q == nil)
 
1013
                        q = p->pcond;
 
1014
                if(q->mark&FOLL) {
 
1015
                        p->pcond = q;
 
1016
                        return;
 
1017
                }
 
1018
                p = q;
 
1019
                goto loop;
 
1020
        }
 
1021
        p = p->link;
 
1022
        goto loop;
 
1023
}
 
1024
 
 
1025
LinkArch linkarm = {
 
1026
        .name = "arm",
 
1027
        .thechar = '5',
 
1028
 
 
1029
        .addstacksplit = addstacksplit,
 
1030
        .assemble = span5,
 
1031
        .datasize = datasize,
 
1032
        .follow = follow,
 
1033
        .iscall = iscall,
 
1034
        .isdata = isdata,
 
1035
        .prg = prg,
 
1036
        .progedit = progedit,
 
1037
        .settextflag = settextflag,
 
1038
        .symtype = symtype,
 
1039
        .textflag = textflag,
 
1040
 
 
1041
        .minlc = 4,
 
1042
        .ptrsize = 4,
 
1043
        .regsize = 4,
 
1044
 
 
1045
        .D_ADDR = D_ADDR,
 
1046
        .D_AUTO = D_AUTO,
 
1047
        .D_BRANCH = D_BRANCH,
 
1048
        .D_CONST = D_CONST,
 
1049
        .D_EXTERN = D_EXTERN,
 
1050
        .D_FCONST = D_FCONST,
 
1051
        .D_NONE = D_NONE,
 
1052
        .D_PARAM = D_PARAM,
 
1053
        .D_SCONST = D_SCONST,
 
1054
        .D_STATIC = D_STATIC,
 
1055
 
 
1056
        .ACALL = ABL,
 
1057
        .ADATA = ADATA,
 
1058
        .AEND = AEND,
 
1059
        .AFUNCDATA = AFUNCDATA,
 
1060
        .AGLOBL = AGLOBL,
 
1061
        .AJMP = AB,
 
1062
        .ANOP = ANOP,
 
1063
        .APCDATA = APCDATA,
 
1064
        .ARET = ARET,
 
1065
        .ATEXT = ATEXT,
 
1066
        .ATYPE = ATYPE,
 
1067
        .AUSEFIELD = AUSEFIELD,
 
1068
};