diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
commit | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch) | |
tree | 4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/cmd/5l | |
parent | c8bf49ef8a92e2337b69c14b9b88396efe498600 (diff) | |
download | golang-upstream/1.3.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/cmd/5l')
-rw-r--r-- | src/cmd/5l/5.out.h | 85 | ||||
-rw-r--r-- | src/cmd/5l/asm.c | 1542 | ||||
-rw-r--r-- | src/cmd/5l/l.h | 349 | ||||
-rw-r--r-- | src/cmd/5l/list.c | 427 | ||||
-rw-r--r-- | src/cmd/5l/noop.c | 671 | ||||
-rw-r--r-- | src/cmd/5l/obj.c | 731 | ||||
-rw-r--r-- | src/cmd/5l/optab.c | 277 | ||||
-rw-r--r-- | src/cmd/5l/pass.c | 409 | ||||
-rw-r--r-- | src/cmd/5l/prof.c | 211 | ||||
-rw-r--r-- | src/cmd/5l/softfloat.c | 91 | ||||
-rw-r--r-- | src/cmd/5l/span.c | 937 |
11 files changed, 219 insertions, 5511 deletions
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h index e8cf83ddd..9e8aceecb 100644 --- a/src/cmd/5l/5.out.h +++ b/src/cmd/5l/5.out.h @@ -198,6 +198,12 @@ enum as AFUNCDATA, APCDATA, ACHECKNIL, + AVARDEF, + AVARKILL, + ADUFFCOPY, + ADUFFZERO, + + AMRC, // MRC/MCR ALAST, }; @@ -233,62 +239,43 @@ enum as #define SHIFT_AR 2<<5 #define SHIFT_RR 3<<5 +enum +{ /* type/name */ -#define D_GOK 0 -#define D_NONE 1 + D_GOK = 0, + D_NONE = 1, /* type */ -#define D_BRANCH (D_NONE+1) -#define D_OREG (D_NONE+2) -#define D_CONST (D_NONE+7) -#define D_FCONST (D_NONE+8) -#define D_SCONST (D_NONE+9) -#define D_PSR (D_NONE+10) -#define D_REG (D_NONE+12) -#define D_FREG (D_NONE+13) -#define D_FILE (D_NONE+16) -#define D_OCONST (D_NONE+17) -#define D_FILE1 (D_NONE+18) - -#define D_SHIFT (D_NONE+19) -#define D_FPCR (D_NONE+20) -#define D_REGREG (D_NONE+21) // (reg, reg) -#define D_ADDR (D_NONE+22) - -#define D_SBIG (D_NONE+23) -#define D_CONST2 (D_NONE+24) - -#define D_REGREG2 (D_NONE+25) // reg, reg + D_BRANCH = (D_NONE+1), + D_OREG = (D_NONE+2), + D_CONST = (D_NONE+7), + D_FCONST = (D_NONE+8), + D_SCONST = (D_NONE+9), + D_PSR = (D_NONE+10), + D_REG = (D_NONE+12), + D_FREG = (D_NONE+13), + D_FILE = (D_NONE+16), + D_OCONST = (D_NONE+17), + D_FILE1 = (D_NONE+18), + + D_SHIFT = (D_NONE+19), + D_FPCR = (D_NONE+20), + D_REGREG = (D_NONE+21), // (reg, reg) + D_ADDR = (D_NONE+22), + + D_SBIG = (D_NONE+23), + D_CONST2 = (D_NONE+24), + + D_REGREG2 = (D_NONE+25), // reg, reg /* name */ -#define D_EXTERN (D_NONE+3) -#define D_STATIC (D_NONE+4) -#define D_AUTO (D_NONE+5) -#define D_PARAM (D_NONE+6) - -/* internal only */ -#define D_SIZE (D_NONE+40) -#define D_PCREL (D_NONE+41) -#define D_GOTOFF (D_NONE+42) // R_ARM_GOTOFF -#define D_PLT0 (D_NONE+43) // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000 -#define D_PLT1 (D_NONE+44) // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000 -#define D_PLT2 (D_NONE+45) // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]! -#define D_CALL (D_NONE+46) // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy -#define D_TLS (D_NONE+47) // R_ARM_TLS_LE32 + D_EXTERN = (D_NONE+3), + D_STATIC = (D_NONE+4), + D_AUTO = (D_NONE+5), + D_PARAM = (D_NONE+6), +}; /* * this is the ranlib header */ #define SYMDEF "__.GOSYMDEF" - -/* - * this is the simulated IEEE floating point - */ -typedef struct ieee Ieee; -struct ieee -{ - int32 l; /* contains ls-man 0xffffffff */ - int32 h; /* contains sign 0x80000000 - exp 0x7ff00000 - ms-man 0x000fffff */ -}; diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 33cdf8096..5e9267b5b 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -35,43 +35,26 @@ #include "../ld/elf.h" #include "../ld/dwarf.h" -static Prog *PP; char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; char openbsddynld[] = "XXX"; char netbsddynld[] = "/libexec/ld.elf_so"; char dragonflydynld[] = "XXX"; - -int32 -entryvalue(void) -{ - char *a; - Sym *s; - - a = INITENTRY; - if(*a >= '0' && *a <= '9') - return atolwhex(a); - s = lookup(a, 0); - if(s->type == 0) - return INITTEXT; - if(s->type != STEXT) - diag("entry not text: %s", s->name); - return s->value; -} +char solarisdynld[] = "XXX"; static int needlib(char *name) { char *p; - Sym *s; + LSym *s; if(*name == '\0') return 0; /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); - s = lookup(p, 0); + s = linklookup(ctxt, p, 0); free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -82,9 +65,9 @@ needlib(char *name) int nelfsym = 1; -static void addpltsym(Sym*); -static void addgotsym(Sym*); -static void addgotsyminternal(Sym*); +static void addpltsym(Link*, LSym*); +static void addgotsym(Link*, LSym*); +static void addgotsyminternal(Link*, LSym*); // Preserve highest 8 bits of a, and do addition to lower 24-bit // of a and b; used to adjust ARM branch intruction's target @@ -95,19 +78,19 @@ braddoff(int32 a, int32 b) } void -adddynrela(Sym *rel, Sym *s, Reloc *r) +adddynrela(LSym *rel, LSym *s, Reloc *r) { - addaddrplus(rel, s, r->off); - adduint32(rel, R_ARM_RELATIVE); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, R_ARM_RELATIVE); } void -adddynrel(Sym *s, Reloc *r) +adddynrel(LSym *s, Reloc *r) { - Sym *targ, *rel; + LSym *targ, *rel; targ = r->sym; - cursym = s; + ctxt->cursym = s; switch(r->type) { default: @@ -119,10 +102,10 @@ adddynrel(Sym *s, Reloc *r) // Handle relocations found in ELF object files. case 256 + R_ARM_PLT32: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -134,54 +117,54 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } - r->type = D_CONST; // write r->add during relocsym + r->type = R_CONST; // write r->add during relocsym r->sym = S; r->add += targ->got; return; case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P if(targ->type != SDYNIMPORT) { - addgotsyminternal(targ); + addgotsyminternal(ctxt, targ); } else { - addgotsym(targ); + addgotsym(ctxt, targ); } - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += targ->got + 4; return; case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32 - r->type = D_GOTOFF; + r->type = R_GOTOFF; return; case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL - r->type = D_PCREL; - r->sym = lookup(".got", 0); + r->type = R_PCREL; + r->sym = linklookup(ctxt, ".got", 0); r->add += 4; return; case 256 + R_ARM_CALL: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; case 256 + R_ARM_REL32: // R_ARM_REL32 - r->type = D_PCREL; + r->type = R_PCREL; r->add += 4; return; case 256 + R_ARM_ABS32: if(targ->type == SDYNIMPORT) diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name); - r->type = D_ADDR; + r->type = R_ADDR; return; case 256 + R_ARM_V4BX: @@ -195,10 +178,10 @@ adddynrel(Sym *s, Reloc *r) case 256 + R_ARM_PC24: case 256 + R_ARM_JUMP24: - r->type = D_CALL; + r->type = R_CALLARM; if(targ->type == SDYNIMPORT) { - addpltsym(targ); - r->sym = lookup(".plt", 0); + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = braddoff(r->add, targ->plt / 4); } return; @@ -209,28 +192,28 @@ adddynrel(Sym *s, Reloc *r) return; switch(r->type) { - case D_PCREL: - addpltsym(targ); - r->sym = lookup(".plt", 0); + case R_CALLARM: + addpltsym(ctxt, targ); + r->sym = linklookup(ctxt, ".plt", 0); r->add = targ->plt; return; - case D_ADDR: + case R_ADDR: if(s->type != SDATA) break; if(iself) { - adddynsym(targ); - rel = lookup(".rel", 0); - addaddrplus(rel, s, r->off); - adduint32(rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc - r->type = D_CONST; // write r->add during relocsym + adddynsym(ctxt, targ); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, s, r->off); + adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc + r->type = R_CONST; // write r->add during relocsym r->sym = S; return; } break; } - cursym = s; + ctxt->cursym = s; diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type); } @@ -246,21 +229,21 @@ elfreloc1(Reloc *r, vlong sectoff) default: return -1; - case D_ADDR: + case R_ADDR: if(r->siz == 4) LPUT(R_ARM_ABS32 | elfsym<<8); else return -1; break; - case D_PCREL: + case R_PCREL: if(r->siz == 4) LPUT(R_ARM_REL32 | elfsym<<8); else return -1; break; - case D_CALL: + case R_CALLARM: if(r->siz == 4) { if((r->add & 0xff000000) == 0xeb000000) // BL LPUT(R_ARM_CALL | elfsym<<8); @@ -270,7 +253,7 @@ elfreloc1(Reloc *r, vlong sectoff) return -1; break; - case D_TLS: + case R_TLS: if(r->siz == 4) { if(flag_shared) LPUT(R_ARM_TLS_IE32 | elfsym<<8); @@ -287,26 +270,26 @@ elfreloc1(Reloc *r, vlong sectoff) void elfsetupplt(void) { - Sym *plt, *got; + LSym *plt, *got; - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); if(plt->size == 0) { // str lr, [sp, #-4]! - adduint32(plt, 0xe52de004); + adduint32(ctxt, plt, 0xe52de004); // ldr lr, [pc, #4] - adduint32(plt, 0xe59fe004); + adduint32(ctxt, plt, 0xe59fe004); // add lr, pc, lr - adduint32(plt, 0xe08fe00e); + adduint32(ctxt, plt, 0xe08fe00e); // ldr pc, [lr, #8]! - adduint32(plt, 0xe5bef008); + adduint32(ctxt, plt, 0xe5bef008); // .word &GLOBAL_OFFSET_TABLE[0] - . - addpcrelplus(plt, got, 4); + addpcrelplus(ctxt, plt, got, 4); // the first .plt entry requires 3 .plt.got entries - adduint32(got, 0); - adduint32(got, 0); - adduint32(got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); + adduint32(ctxt, got, 0); } } @@ -321,13 +304,13 @@ machoreloc1(Reloc *r, vlong sectoff) int -archreloc(Reloc *r, Sym *s, vlong *val) +archreloc(Reloc *r, LSym *s, vlong *val) { - Sym *rs; + LSym *rs; if(linkmode == LinkExternal) { switch(r->type) { - case D_CALL: + case R_CALLARM: r->done = 0; // set up addend for eventual relocation via outer symbol. @@ -352,29 +335,29 @@ archreloc(Reloc *r, Sym *s, vlong *val) return -1; } switch(r->type) { - case D_CONST: + case R_CONST: *val = r->add; return 0; - case D_GOTOFF: - *val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0)); + case R_GOTOFF: + *val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0)); return 0; // The following three arch specific relocations are only for generation of // Linux/ARM ELF's PLT entry (3 assembler instruction) - case D_PLT0: // add ip, pc, #0xXX00000 - if (symaddr(lookup(".got.plt", 0)) < symaddr(lookup(".plt", 0))) + case R_PLT0: // add ip, pc, #0xXX00000 + if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0))) diag(".got.plt should be placed after .plt section."); *val = 0xe28fc600U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add) >> 20)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20)); return 0; - case D_PLT1: // add ip, ip, #0xYY000 + case R_PLT1: // add ip, ip, #0xYY000 *val = 0xe28cca00U + - (0xff & ((uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 4) >> 12)); + (0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12)); return 0; - case D_PLT2: // ldr pc, [ip, #0xZZZ]! + case R_PLT2: // ldr pc, [ip, #0xZZZ]! *val = 0xe5bcf000U + - (0xfff & (uint32)(symaddr(r->sym) - (symaddr(lookup(".plt", 0)) + r->off) + r->add + 8)); + (0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8)); return 0; - case D_CALL: // bl XXXXXX or b YYYYYY + case R_CALLARM: // bl XXXXXX or b YYYYYY *val = braddoff((0xff000000U & (uint32)r->add), (0xffffff & (uint32) ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4))); @@ -384,7 +367,7 @@ archreloc(Reloc *r, Sym *s, vlong *val) } static Reloc * -addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) +addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ) { Reloc *r; @@ -397,25 +380,25 @@ addpltreloc(Sym *plt, Sym *got, Sym *sym, int typ) plt->reachable = 1; plt->size += 4; - symgrow(plt, plt->size); + symgrow(ctxt, plt, plt->size); return r; } static void -addpltsym(Sym *s) +addpltsym(Link *ctxt, LSym *s) { - Sym *plt, *got, *rel; + LSym *plt, *got, *rel; if(s->plt >= 0) return; - adddynsym(s); + adddynsym(ctxt, s); if(iself) { - plt = lookup(".plt", 0); - got = lookup(".got.plt", 0); - rel = lookup(".rel.plt", 0); + plt = linklookup(ctxt, ".plt", 0); + got = linklookup(ctxt, ".got.plt", 0); + rel = linklookup(ctxt, ".rel.plt", 0); if(plt->size == 0) elfsetupplt(); @@ -424,34 +407,34 @@ addpltsym(Sym *s) // In theory, all GOT should point to the first PLT entry, // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's // dynamic linker won't, so we'd better do it ourselves. - addaddrplus(got, plt, 0); + addaddrplus(ctxt, got, plt, 0); // .plt entry, this depends on the .got entry s->plt = plt->size; - addpltreloc(plt, got, s, D_PLT0); // add lr, pc, #0xXX00000 - addpltreloc(plt, got, s, D_PLT1); // add lr, lr, #0xYY000 - addpltreloc(plt, got, s, D_PLT2); // ldr pc, [lr, #0xZZZ]! + addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000 + addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000 + addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]! // rel - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT)); } else { diag("addpltsym: unsupported binary format"); } } static void -addgotsyminternal(Sym *s) +addgotsyminternal(Link *ctxt, LSym *s) { - Sym *got; + LSym *got; if(s->got >= 0) return; - got = lookup(".got", 0); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - addaddrplus(got, s, 0); + addaddrplus(ctxt, got, s, 0); if(iself) { ; @@ -461,31 +444,31 @@ addgotsyminternal(Sym *s) } static void -addgotsym(Sym *s) +addgotsym(Link *ctxt, LSym *s) { - Sym *got, *rel; + LSym *got, *rel; if(s->got >= 0) return; - adddynsym(s); - got = lookup(".got", 0); + adddynsym(ctxt, s); + got = linklookup(ctxt, ".got", 0); s->got = got->size; - adduint32(got, 0); + adduint32(ctxt, got, 0); if(iself) { - rel = lookup(".rel", 0); - addaddrplus(rel, got, s->got); - adduint32(rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); + rel = linklookup(ctxt, ".rel", 0); + addaddrplus(ctxt, rel, got, s->got); + adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT)); } else { diag("addgotsym: unsupported binary format"); } } void -adddynsym(Sym *s) +adddynsym(Link *ctxt, LSym *s) { - Sym *d; + LSym *d; int t; char *name; @@ -495,20 +478,20 @@ adddynsym(Sym *s) if(iself) { s->dynid = nelfsym++; - d = lookup(".dynsym", 0); + d = linklookup(ctxt, ".dynsym", 0); /* name */ name = s->extname; - adduint32(d, addstring(lookup(".dynstr", 0), name)); + adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name)); /* value */ if(s->type == SDYNIMPORT) - adduint32(d, 0); + adduint32(ctxt, d, 0); else - addaddr(d, s); + addaddr(ctxt, d, s); /* size */ - adduint32(d, 0); + adduint32(ctxt, d, 0); /* type */ t = STB_GLOBAL << 4; @@ -516,12 +499,12 @@ adddynsym(Sym *s) t |= STT_FUNC; else t |= STT_OBJECT; - adduint8(d, t); - adduint8(d, 0); + adduint8(ctxt, d, t); + adduint8(ctxt, d, 0); /* shndx */ if(s->type == SDYNIMPORT) - adduint16(d, SHN_UNDEF); + adduint16(ctxt, d, SHN_UNDEF); else { switch(s->type) { default: @@ -538,7 +521,7 @@ adddynsym(Sym *s) t = 14; break; } - adduint16(d, t); + adduint16(ctxt, d, t); } } else { diag("adddynsym: unsupported binary format"); @@ -548,39 +531,27 @@ adddynsym(Sym *s) void adddynlib(char *lib) { - Sym *s; + LSym *s; if(!needlib(lib)) return; if(iself) { - s = lookup(".dynstr", 0); + s = linklookup(ctxt, ".dynstr", 0); if(s->size == 0) addstring(s, ""); - elfwritedynent(lookup(".dynamic", 0), DT_NEEDED, addstring(s, lib)); + elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); } else { diag("adddynlib: unsupported binary format"); } } -vlong -datoff(vlong addr) -{ - if(addr >= segdata.vaddr) - return addr - segdata.vaddr + segdata.fileoff; - if(addr >= segtext.vaddr) - return addr - segtext.vaddr + segtext.fileoff; - diag("datoff %#x", addr); - return 0; -} - void asmb(void) { - int32 t; uint32 symo; Section *sect; - Sym *sym; + LSym *sym; int i; if(debug['v']) @@ -627,13 +598,7 @@ asmb(void) default: if(iself) goto ElfSym; - case Hnoheader: - case Hrisc: - case Hixp1200: - case Hipaq: - debug['s'] = 1; - break; - case Hplan9x32: + case Hplan9: symo = HEADR+segtext.len+segdata.filelen; break; ElfSym: @@ -659,11 +624,11 @@ asmb(void) elfemitreloc(); } break; - case Hplan9x32: + case Hplan9: asmplan9sym(); cflush(); - sym = lookup("pclntab", 0); + sym = linklookup(ctxt, "pclntab", 0); if(sym != nil) { lcsize = sym->np; for(i=0; i < lcsize; i++) @@ -675,46 +640,14 @@ asmb(void) } } - cursym = nil; + ctxt->cursym = nil; if(debug['v']) Bprint(&bso, "%5.2f header\n", cputime()); Bflush(&bso); cseek(0L); switch(HEADTYPE) { default: - case Hnoheader: /* no header */ - break; - case Hrisc: /* aif for risc os */ - lputl(0xe1a00000); /* NOP - decompress code */ - lputl(0xe1a00000); /* NOP - relocation code */ - lputl(0xeb000000 + 12); /* BL - zero init code */ - lputl(0xeb000000 + - (entryvalue() - - INITTEXT - + HEADR - - 12 - - 8) / 4); /* BL - entry code */ - - lputl(0xef000011); /* SWI - exit code */ - lputl(segtext.filelen+HEADR); /* text size */ - lputl(segdata.filelen); /* data size */ - lputl(0); /* sym size */ - - lputl(segdata.len - segdata.filelen); /* bss size */ - lputl(0); /* sym type */ - lputl(INITTEXT-HEADR); /* text addr */ - lputl(0); /* workspace - ignored */ - - lputl(32); /* addr mode / data addr flag */ - lputl(0); /* data addr */ - for(t=0; t<2; t++) - lputl(0); /* reserved */ - - for(t=0; t<15; t++) - lputl(0xe1a00000); /* NOP - zero init code */ - lputl(0xe1a0f00e); /* B (R14) - zero init return */ - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ lput(0x647); /* magic */ lput(segtext.filelen); /* sizes */ lput(segdata.filelen); @@ -724,14 +657,6 @@ asmb(void) lput(0L); lput(lcsize); break; - case Hixp1200: /* boot for IXP1200 */ - break; - case Hipaq: /* boot for ipaq */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - lputl(0xe3300000); /* nop */ - break; case Hlinux: case Hfreebsd: case Hnetbsd: @@ -808,1224 +733,17 @@ nopstat(char *f, Count *c) (double)(c->outof - c->count)/c->outof); } -void -asmout(Prog *p, Optab *o, int32 *out, Sym *gmsym) -{ - int32 o1, o2, o3, o4, o5, o6, v; - int r, rf, rt, rt2; - Reloc *rel; - -PP = p; - o1 = 0; - o2 = 0; - o3 = 0; - o4 = 0; - o5 = 0; - o6 = 0; - armsize += o->size; -if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type); - switch(o->type) { - default: - diag("unknown asm %d", o->type); - prasm(p); - break; - - case 0: /* pseudo ops */ -if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr); - break; - - case 1: /* op R,[R],R */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN) - r = 0; - else - if(r == NREG) - r = rt; - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 2: /* movbu $I,[R],R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= immrot(instoffset); - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 3: /* add R<<[IR],[R],R */ - mov: - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - o1 |= p->from.offset; - rt = p->to.reg; - r = p->reg; - if(p->to.type == D_NONE) - rt = 0; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 4: /* add $I,[R],R */ - aclass(&p->from); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 |= r << 16; - o1 |= p->to.reg << 12; - break; - - case 5: /* bra s */ - o1 = opbra(p->as, p->scond); - v = -8; - if(p->to.sym != S && p->to.sym->type != 0) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = o1 | ((v >> 2) & 0xffffff); - rel->type = D_CALL; - break; - } - if(p->cond != P) - v = (p->cond->pc - pc) - 8; - o1 |= (v >> 2) & 0xffffff; - break; - - case 6: /* b ,O(R) -> add $O,R,PC */ - aclass(&p->to); - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGPC << 12; - break; - - case 7: /* bl (R) -> blx R */ - aclass(&p->to); - if(instoffset != 0) - diag("%P: doesn't support BL offset(REG) where offset != 0", p); - o1 = oprrr(ABL, p->scond); - o1 |= p->to.reg; - break; - - case 8: /* sll $c,[R],R -> mov (R<<$c),R */ - aclass(&p->from); - o1 = oprrr(p->as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (instoffset&31) << 7; - o1 |= p->to.reg << 12; - break; - - case 9: /* sll R,[R],R -> mov (R<<R),R */ - o1 = oprrr(p->as, p->scond); - r = p->reg; - if(r == NREG) - r = p->to.reg; - o1 |= r; - o1 |= (p->from.reg << 8) | (1<<4); - o1 |= p->to.reg << 12; - break; - - case 10: /* swi [$con] */ - o1 = oprrr(p->as, p->scond); - if(p->to.type != D_NONE) { - aclass(&p->to); - o1 |= instoffset & 0xffffff; - } - break; - - case 11: /* word */ - aclass(&p->to); - o1 = instoffset; - if(p->to.sym != S) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - rel->sym = p->to.sym; - rel->add = p->to.offset; - if(rel->sym == gmsym) { - rel->type = D_TLS; - if(flag_shared) - rel->add += pc - p->pcrel->pc - 8 - rel->siz; - rel->xadd = rel->add; - rel->xsym = rel->sym; - } else if(flag_shared) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 8; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - case 12: /* movw $lcon, reg */ - o1 = omvl(p, &p->from, p->to.reg); - if(o->flag & LPCREL) { - o2 = oprrr(AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12; - } - break; - - case 13: /* op $lcon, [R], R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = oprrr(p->as, p->scond); - o2 |= REGTMP; - r = p->reg; - if(p->as == AMOVW || p->as == AMVN) - r = 0; - else if(r == NREG) - r = p->to.reg; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 14: /* movb/movbu/movh/movhu R,R */ - o1 = oprrr(ASLL, p->scond); - - if(p->as == AMOVBU || p->as == AMOVHU) - o2 = oprrr(ASRL, p->scond); - else - o2 = oprrr(ASRA, p->scond); - - r = p->to.reg; - o1 |= (p->from.reg)|(r<<12); - o2 |= (r)|(r<<12); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) { - o1 |= (24<<7); - o2 |= (24<<7); - } else { - o1 |= (16<<7); - o2 |= (16<<7); - } - break; - - case 15: /* mul r,[r,]r */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) - r = rt; - if(rt == r) { - r = rf; - rf = rt; - } - if(0) - if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) { - diag("bad registers in MUL"); - prasm(p); - } - o1 |= (rf<<8) | r | (rt<<16); - break; - - - case 16: /* div r,[r,]r */ - o1 = 0xf << 28; - o2 = 0; - break; - - case 17: - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - rt2 = p->to.offset; - r = p->reg; - o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12); - break; - - case 20: /* mov/movb/movbu R,O(R) */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = osr(p->as, p->from.reg, instoffset, r, p->scond); - break; - - case 21: /* mov/movbu O(R),R -> lr */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olr(instoffset, r, p->to.reg, p->scond); - if(p->as != AMOVW) - o1 |= 1<<22; - break; - - case 30: /* mov/movb/movbu R,L(R) */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = osrr(p->from.reg, REGTMP,r, p->scond); - if(p->as != AMOVW) - o2 |= 1<<22; - break; - - case 31: /* mov/movbu L(R),R -> lr[b] */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olrr(REGTMP,r, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - break; - - case 34: /* mov $lacon,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - - o2 = oprrr(AADD, p->scond); - o2 |= REGTMP; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 |= r << 16; - if(p->to.type != D_NONE) - o2 |= p->to.reg << 12; - break; - - case 35: /* mov PSR,R */ - o1 = (2<<23) | (0xf<<16) | (0<<0); - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->from.reg & 1) << 22; - o1 |= p->to.reg << 12; - break; - - case 36: /* mov R,PSR */ - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 37: /* mov $con,PSR */ - aclass(&p->from); - o1 = (2<<23) | (0x29f<<12) | (0<<4); - if(p->scond & C_FBIT) - o1 ^= 0x010 << 12; - o1 |= (p->scond & C_SCOND) << 28; - o1 |= immrot(instoffset); - o1 |= (p->to.reg & 1) << 22; - o1 |= p->from.reg << 0; - break; - - case 38: /* movm $con,oreg -> stm */ - o1 = (0x4 << 25); - o1 |= p->from.offset & 0xffff; - o1 |= p->to.reg << 16; - aclass(&p->to); - goto movm; - - case 39: /* movm oreg,$con -> ldm */ - o1 = (0x4 << 25) | (1 << 20); - o1 |= p->to.offset & 0xffff; - o1 |= p->from.reg << 16; - aclass(&p->from); - movm: - if(instoffset != 0) - diag("offset must be zero in MOVM"); - o1 |= (p->scond & C_SCOND) << 28; - if(p->scond & C_PBIT) - o1 |= 1 << 24; - if(p->scond & C_UBIT) - o1 |= 1 << 23; - if(p->scond & C_SBIT) - o1 |= 1 << 22; - if(p->scond & C_WBIT) - o1 |= 1 << 21; - break; - - case 40: /* swp oreg,reg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in SWP"); - o1 = (0x2<<23) | (0x9<<4); - if(p->as != ASWPW) - o1 |= 1 << 22; - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - - case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */ - o1 = 0xe8fd8000; - break; - - case 50: /* floating point store */ - v = regoff(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->from.reg, v, r, p->scond, p); - break; - - case 51: /* floating point load */ - v = regoff(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = ofsr(p->as, p->to.reg, v, r, p->scond, p) | (1<<20); - break; - - case 52: /* floating point store, int32 offset UGLY */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - break; - - case 53: /* floating point load, int32 offset UGLY */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = oprrr(AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r; - o3 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - break; - - case 54: /* floating point arith */ - o1 = oprrr(p->as, p->scond); - rf = p->from.reg; - rt = p->to.reg; - r = p->reg; - if(r == NREG) { - r = rt; - if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD || p->as == AABSF || p->as == AABSD) - r = 0; - } - o1 |= rf | (r<<16) | (rt<<12); - break; - - case 56: /* move to FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12); - break; - - case 57: /* move from FP[CS]R */ - o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4); - o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20); - break; - case 58: /* movbu R,R */ - o1 = oprrr(AAND, p->scond); - o1 |= immrot(0xff); - rt = p->to.reg; - r = p->from.reg; - if(p->to.type == D_NONE) - rt = 0; - if(r == NREG) - r = rt; - o1 |= (r<<16) | (rt<<12); - break; - - case 59: /* movw/bu R<<I(R),R -> ldr indexed */ - if(p->from.reg == NREG) { - if(p->as != AMOVW) - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(1<<4)) - diag("bad shift in LDR"); - o1 = olrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - if(p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 60: /* movb R(R),R -> ldrsb indexed */ - if(p->from.reg == NREG) { - diag("byte MOV from shifter operand"); - goto mov; - } - if(p->from.offset&(~0xf)) - diag("bad shift in LDRSB"); - o1 = olhrr(p->from.offset, p->from.reg, p->to.reg, p->scond); - o1 ^= (1<<5)|(1<<6); - break; - - case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */ - if(p->to.reg == NREG) - diag("MOV to shifter operand"); - o1 = osrr(p->from.reg, p->to.offset, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) - o1 |= 1<<22; - break; - - case 62: /* case R -> movw R<<2(PC),PC */ - if(o->flag & LPCREL) { - o1 = oprrr(AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12; - o2 = olrr(REGTMP, REGPC, REGTMP, p->scond); - o2 |= 2<<7; - o3 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12; - } else { - o1 = olrr(p->from.reg, REGPC, REGPC, p->scond); - o1 |= 2<<7; - } - break; - - case 63: /* bcase */ - if(p->cond != P) { - rel = addrel(cursym); - rel->off = pc - cursym->value; - rel->siz = 4; - if(p->to.sym != S && p->to.sym->type != 0) { - rel->sym = p->to.sym; - rel->add = p->to.offset; - } else { - rel->sym = cursym; - rel->add = p->cond->pc - cursym->value; - } - if(o->flag & LPCREL) { - rel->type = D_PCREL; - rel->add += pc - p->pcrel->pc - 16 + rel->siz; - } else - rel->type = D_ADDR; - o1 = 0; - } - break; - - /* reloc ops */ - case 64: /* mov/movb/movbu R,addr */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 65: /* mov/movbu addr,R */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB) - o2 |= 1<<22; - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 68: /* floating point store -> ADDR */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->from.reg, 0, REGTMP, p->scond, p); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - case 69: /* floating point load <- ADDR */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = ofsr(p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - - /* ArmV4 ops: */ - case 70: /* movh/movhu R,O(R) -> strh */ - aclass(&p->to); - r = p->to.reg; - if(r == NREG) - r = o->param; - o1 = oshr(p->from.reg, instoffset, r, p->scond); - break; - case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */ - aclass(&p->from); - r = p->from.reg; - if(r == NREG) - r = o->param; - o1 = olhr(instoffset, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o1 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o1 ^= (1<<6); - break; - case 72: /* movh/movhu R,L(R) -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - r = p->to.reg; - if(r == NREG) - r = o->param; - o2 = oshrr(p->from.reg, REGTMP,r, p->scond); - break; - case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - r = p->from.reg; - if(r == NREG) - r = o->param; - o2 = olhrr(REGTMP, r, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - break; - case 74: /* bx $I */ - diag("ABX $I"); - break; - case 75: /* bx O(R) */ - aclass(&p->to); - if(instoffset != 0) - diag("non-zero offset in ABX"); -/* - o1 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R -*/ - // p->to.reg may be REGLINK - o1 = oprrr(AADD, p->scond); - o1 |= immrot(instoffset); - o1 |= p->to.reg << 16; - o1 |= REGTMP << 12; - o2 = oprrr(AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12); // mov PC, LR - o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp - break; - case 76: /* bx O(R) when returning from fn*/ - diag("ABXRET"); - break; - case 77: /* ldrex oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x19<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 78: /* strex reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x18<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 80: /* fmov zfcon,freg */ - if(p->as == AMOVD) { - o1 = 0xeeb00b00; // VMOV imm 64 - o2 = oprrr(ASUBD, p->scond); - } else { - o1 = 0x0eb00a00; // VMOV imm 32 - o2 = oprrr(ASUBF, p->scond); - } - v = 0x70; // 1.0 - r = p->to.reg; - - // movf $1.0, r - o1 |= (p->scond & C_SCOND) << 28; - o1 |= r << 12; - o1 |= (v&0xf) << 0; - o1 |= (v&0xf0) << 12; - - // subf r,r,r - o2 |= r | (r<<16) | (r<<12); - break; - case 81: /* fmov sfcon,freg */ - o1 = 0x0eb00a00; // VMOV imm 32 - if(p->as == AMOVD) - o1 = 0xeeb00b00; // VMOV imm 64 - o1 |= (p->scond & C_SCOND) << 28; - o1 |= p->to.reg << 12; - v = chipfloat(&p->from.ieee); - o1 |= (v&0xf) << 0; - o1 |= (v&0xf0) << 12; - break; - case 82: /* fcmp freg,freg, */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->reg<<12) | (p->from.reg<<0); - o2 = 0x0ef1fa10; // VMRS R15 - o2 |= (p->scond & C_SCOND) << 28; - break; - case 83: /* fcmp freg,, */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<12) | (1<<16); - o2 = 0x0ef1fa10; // VMRS R15 - o2 |= (p->scond & C_SCOND) << 28; - break; - case 84: /* movfw freg,freg - truncate float-to-fix */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (p->to.reg<<12); - break; - case 85: /* movwf freg,freg - fix-to-float */ - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (p->to.reg<<12); - break; - case 86: /* movfw freg,reg - truncate float-to-fix */ - // macro for movfw freg,FTMP; movw FTMP,reg - o1 = oprrr(p->as, p->scond); - o1 |= (p->from.reg<<0); - o1 |= (FREGTMP<<12); - o2 = oprrr(AMOVFW+AEND, p->scond); - o2 |= (FREGTMP<<16); - o2 |= (p->to.reg<<12); - break; - case 87: /* movwf reg,freg - fix-to-float */ - // macro for movw reg,FTMP; movwf FTMP,freg - o1 = oprrr(AMOVWF+AEND, p->scond); - o1 |= (p->from.reg<<12); - o1 |= (FREGTMP<<16); - o2 = oprrr(p->as, p->scond); - o2 |= (FREGTMP<<0); - o2 |= (p->to.reg<<12); - break; - case 88: /* movw reg,freg */ - o1 = oprrr(AMOVWF+AEND, p->scond); - o1 |= (p->from.reg<<12); - o1 |= (p->to.reg<<16); - break; - case 89: /* movw freg,reg */ - o1 = oprrr(AMOVFW+AEND, p->scond); - o1 |= (p->from.reg<<16); - o1 |= (p->to.reg<<12); - break; - case 90: /* tst reg */ - o1 = oprrr(ACMP+AEND, p->scond); - o1 |= p->from.reg<<16; - break; - case 91: /* ldrexd oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in LDREX"); - o1 = (0x1b<<20) | (0xf9f); - o1 |= p->from.reg << 16; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 92: /* strexd reg,oreg,reg */ - aclass(&p->from); - if(instoffset != 0) - diag("offset must be zero in STREX"); - o1 = (0x1a<<20) | (0xf90); - o1 |= p->from.reg << 16; - o1 |= p->reg << 0; - o1 |= p->to.reg << 12; - o1 |= (p->scond & C_SCOND) << 28; - break; - case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */ - o1 = omvl(p, &p->from, REGTMP); - if(!o1) - break; - o2 = olhr(0, REGTMP, p->to.reg, p->scond); - if(p->as == AMOVB || p->as == AMOVBS) - o2 ^= (1<<5)|(1<<6); - else if(p->as == AMOVH || p->as == AMOVHS) - o2 ^= (1<<6); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 94: /* movh/movhu R,addr -> strh */ - o1 = omvl(p, &p->to, REGTMP); - if(!o1) - break; - o2 = oshr(p->from.reg, 0, REGTMP, p->scond); - if(o->flag & LPCREL) { - o3 = o2; - o2 = oprrr(AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12; - } - break; - case 95: /* PLD off(reg) */ - o1 = 0xf5d0f000; - o1 |= p->from.reg << 16; - if(p->from.offset < 0) { - o1 &= ~(1 << 23); - o1 |= (-p->from.offset) & 0xfff; - } else - o1 |= p->from.offset & 0xfff; - break; - case 96: /* UNDEF */ - // This is supposed to be something that stops execution. - // It's not supposed to be reached, ever, but if it is, we'd - // like to be able to tell how we got there. Assemble as - // 0xf7fabcfd which is guranteed to raise undefined instruction - // exception. - o1 = 0xf7fabcfd; - break; - case 97: /* CLZ Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg; - break; - case 98: /* MULW{T,B} Rs, Rm, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 16; - o1 |= p->from.reg << 8; - o1 |= p->reg; - break; - case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */ - o1 = oprrr(p->as, p->scond); - o1 |= p->to.reg << 12; - o1 |= p->from.reg << 8; - o1 |= p->reg; - o1 |= p->to.offset << 16; - break; - } - - out[0] = o1; - out[1] = o2; - out[2] = o3; - out[3] = o4; - out[4] = o5; - out[5] = o6; - return; - -#ifdef NOTDEF - v = p->pc; - switch(o->size) { - default: - if(debug['a']) - Bprint(&bso, " %.8ux:\t\t%P\n", v, p); - break; - case 4: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p); - lputl(o1); - break; - case 8: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux%P\n", v, o1, o2, p); - lputl(o1); - lputl(o2); - break; - case 12: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux%P\n", v, o1, o2, o3, p); - lputl(o1); - lputl(o2); - lputl(o3); - break; - case 16: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - break; - case 20: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - break; - case 24: - if(debug['a']) - Bprint(&bso, " %.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux%P\n", - v, o1, o2, o3, o4, o5, o6, p); - lputl(o1); - lputl(o2); - lputl(o3); - lputl(o4); - lputl(o5); - lputl(o6); - break; - } -#endif -} - -int32 -oprrr(int a, int sc) -{ - int32 o; - - o = (sc & C_SCOND) << 28; - if(sc & C_SBIT) - o |= 1 << 20; - if(sc & (C_PBIT|C_WBIT)) - diag(".P/.W on dp instruction"); - switch(a) { - case AMULU: - case AMUL: return o | (0x0<<21) | (0x9<<4); - case AMULA: return o | (0x1<<21) | (0x9<<4); - case AMULLU: return o | (0x4<<21) | (0x9<<4); - case AMULL: return o | (0x6<<21) | (0x9<<4); - case AMULALU: return o | (0x5<<21) | (0x9<<4); - case AMULAL: return o | (0x7<<21) | (0x9<<4); - case AAND: return o | (0x0<<21); - case AEOR: return o | (0x1<<21); - case ASUB: return o | (0x2<<21); - case ARSB: return o | (0x3<<21); - case AADD: return o | (0x4<<21); - case AADC: return o | (0x5<<21); - case ASBC: return o | (0x6<<21); - case ARSC: return o | (0x7<<21); - case ATST: return o | (0x8<<21) | (1<<20); - case ATEQ: return o | (0x9<<21) | (1<<20); - case ACMP: return o | (0xa<<21) | (1<<20); - case ACMN: return o | (0xb<<21) | (1<<20); - case AORR: return o | (0xc<<21); - case AMOVB: - case AMOVH: - case AMOVW: return o | (0xd<<21); - case ABIC: return o | (0xe<<21); - case AMVN: return o | (0xf<<21); - case ASLL: return o | (0xd<<21) | (0<<5); - case ASRL: return o | (0xd<<21) | (1<<5); - case ASRA: return o | (0xd<<21) | (2<<5); - case ASWI: return o | (0xf<<24); - - case AADDD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4); - case AADDF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4); - case ASUBD: return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4); - case ASUBF: return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4); - case AMULD: return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4); - case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4); - case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4); - case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4); - case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4); - case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4); - case AABSD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4); - case AABSF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4); - case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4); - case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4); - - case AMOVF: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4); - case AMOVD: return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4); - - case AMOVDF: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | - (1<<8); // dtof - case AMOVFD: return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) | - (0<<8); // dtof - - case AMOVWF: - if((sc & C_UBIT) == 0) - o |= 1<<7; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (0<<18) | (0<<8); // toint, double - case AMOVWD: - if((sc & C_UBIT) == 0) - o |= 1<<7; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (0<<18) | (1<<8); // toint, double - - case AMOVFW: - if((sc & C_UBIT) == 0) - o |= 1<<16; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (1<<18) | (0<<8) | (1<<7); // toint, double, trunc - case AMOVDW: - if((sc & C_UBIT) == 0) - o |= 1<<16; /* signed */ - return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) | - (1<<18) | (1<<8) | (1<<7); // toint, double, trunc - - case AMOVWF+AEND: // copy WtoF - return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4); - case AMOVFW+AEND: // copy FtoW - return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4); - case ACMP+AEND: // cmp imm - return o | (0x3<<24) | (0x5<<20); - - case ACLZ: - // CLZ doesn't support .S - return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4); - - case AMULWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4); - case AMULWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4); - case AMULAWT: - return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4); - case AMULAWB: - return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4); - - case ABL: // BLX REG - return (o & (0xf<<28)) | (0x12fff3 << 4); - } - diag("bad rrr %d", a); - prasm(curp); - return 0; -} - -int32 -opbra(int a, int sc) -{ - - if(sc & (C_SBIT|C_PBIT|C_WBIT)) - diag(".S/.P/.W on bra instruction"); - sc &= C_SCOND; - if(a == ABL) - return (sc<<28)|(0x5<<25)|(0x1<<24); - if(sc != 0xe) - diag(".COND on bcond instruction"); - switch(a) { - case ABEQ: return (0x0<<28)|(0x5<<25); - case ABNE: return (0x1<<28)|(0x5<<25); - case ABCS: return (0x2<<28)|(0x5<<25); - case ABHS: return (0x2<<28)|(0x5<<25); - case ABCC: return (0x3<<28)|(0x5<<25); - case ABLO: return (0x3<<28)|(0x5<<25); - case ABMI: return (0x4<<28)|(0x5<<25); - case ABPL: return (0x5<<28)|(0x5<<25); - case ABVS: return (0x6<<28)|(0x5<<25); - case ABVC: return (0x7<<28)|(0x5<<25); - case ABHI: return (0x8<<28)|(0x5<<25); - case ABLS: return (0x9<<28)|(0x5<<25); - case ABGE: return (0xa<<28)|(0x5<<25); - case ABLT: return (0xb<<28)|(0x5<<25); - case ABGT: return (0xc<<28)|(0x5<<25); - case ABLE: return (0xd<<28)|(0x5<<25); - case AB: return (0xe<<28)|(0x5<<25); - } - diag("bad bra %A", a); - prasm(curp); - return 0; -} - int32 -olr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDR/STR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(!(sc & C_UBIT)) - o |= 1 << 23; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (1<<26) | (1<<20); - if(v < 0) { - if(sc & C_UBIT) diag(".U on neg offset"); - v = -v; - o ^= 1 << 23; - } - if(v >= (1<<12) || v < 0) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); - o |= v; - o |= b << 16; - o |= r << 12; - return o; -} - -int32 -olhr(int32 v, int b, int r, int sc) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on LDRH/STRH instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (1<<23) | (1<<20)|(0xb<<4); - if(v < 0) { - v = -v; - o ^= 1 << 23; - } - if(v >= (1<<8) || v < 0) - diag("literal span too large: %d (R%d)\n%P", v, b, PP); - o |= (v&0xf)|((v>>4)<<8)|(1<<22); - o |= b << 16; - o |= r << 12; - return o; -} - -int32 -osr(int a, int r, int32 v, int b, int sc) -{ - int32 o; - - o = olr(v, b, r, sc) ^ (1<<20); - if(a != AMOVW) - o |= 1<<22; - return o; -} - -int32 -oshr(int r, int32 v, int b, int sc) -{ - int32 o; - - o = olhr(v, b, r, sc) ^ (1<<20); - return o; -} - - -int32 -osrr(int r, int i, int b, int sc) -{ - - return olr(i, b, r, sc) ^ ((1<<25) | (1<<20)); -} - -int32 -oshrr(int r, int i, int b, int sc) -{ - return olhr(i, b, r, sc) ^ ((1<<22) | (1<<20)); -} - -int32 -olrr(int i, int b, int r, int sc) -{ - - return olr(i, b, r, sc) ^ (1<<25); -} - -int32 -olhrr(int i, int b, int r, int sc) -{ - return olhr(i, b, r, sc) ^ (1<<22); -} - -int32 -ofsr(int a, int r, int32 v, int b, int sc, Prog *p) -{ - int32 o; - - if(sc & C_SBIT) - diag(".S on FLDR/FSTR instruction"); - o = (sc & C_SCOND) << 28; - if(!(sc & C_PBIT)) - o |= 1 << 24; - if(sc & C_WBIT) - o |= 1 << 21; - o |= (6<<25) | (1<<24) | (1<<23) | (10<<8); - if(v < 0) { - v = -v; - o ^= 1 << 23; - } - if(v & 3) - diag("odd offset for floating point op: %d\n%P", v, p); - else - if(v >= (1<<10) || v < 0) - diag("literal span too large: %d\n%P", v, p); - o |= (v>>2) & 0xFF; - o |= b << 16; - o |= r << 12; - - switch(a) { - default: - diag("bad fst %A", a); - case AMOVD: - o |= 1 << 8; - case AMOVF: - break; - } - return o; -} - -int32 -omvl(Prog *p, Adr *a, int dr) -{ - int32 v, o1; - if(!p->cond) { - aclass(a); - v = immrot(~instoffset); - if(v == 0) { - diag("missing literal"); - prasm(p); - return 0; - } - o1 = oprrr(AMVN, p->scond&C_SCOND); - o1 |= v; - o1 |= dr << 12; - } else { - v = p->cond->pc - p->pc - 8; - o1 = olr(v, REGPC, dr, p->scond&C_SCOND); - } - return o1; -} - -int -chipzero(Ieee *e) -{ - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7 || e->l != 0 || e->h != 0) - return -1; - return 0; -} - -int -chipfloat(Ieee *e) -{ - int n; - ulong h; - - // We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions. - if(goarm < 7) - goto no; - - if(e->l != 0 || (e->h&0xffff) != 0) - goto no; - h = e->h & 0x7fc00000; - if(h != 0x40000000 && h != 0x3fc00000) - goto no; - n = 0; - - // sign bit (a) - if(e->h & 0x80000000) - n |= 1<<7; - - // exp sign bit (b) - if(h == 0x3fc00000) - n |= 1<<6; - - // rest of exp and mantissa (cd-efgh) - n |= (e->h >> 16) & 0x3f; - -//print("match %.8lux %.8lux %d\n", e->l, e->h, n); - return n; - -no: - return -1; +rnd(int32 v, int32 r) +{ + int32 c; + + if(r <= 0) + return v; + v += r - 1; + c = v % r; + if(c < 0) + c += r; + v -= c; + return v; } diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index ae4b05ba1..761bc861a 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -31,6 +31,7 @@ #include <u.h> #include <libc.h> #include <bio.h> +#include <link.h> #include "5.out.h" enum @@ -38,6 +39,7 @@ enum thechar = '5', PtrSize = 4, IntSize = 4, + RegSize = 4, MaxAlign = 8, // max data alignment FuncAlign = 4 // single-instruction alignment }; @@ -51,167 +53,13 @@ enum #define dynptrsize 0 -typedef struct Adr Adr; -typedef struct Sym Sym; -typedef struct Autom Auto; -typedef struct Prog Prog; -typedef struct Reloc Reloc; -typedef struct Optab Optab; -typedef struct Oprang Oprang; -typedef uchar Opcross[32][2][32]; -typedef struct Count Count; - #define P ((Prog*)0) -#define S ((Sym*)0) -#define TNAME (cursym?cursym->name:noname) - -struct Adr -{ - union - { - struct { - int32 u0offset; - int32 u0offset2; // argsize - } u0off; - char* u0sval; - Ieee u0ieee; - char* u0sbig; - } u0; - Sym* sym; - Sym* gotype; - char type; - char reg; - char name; - char class; -}; - -#define offset u0.u0off.u0offset -#define offset2 u0.u0off.u0offset2 -#define sval u0.u0sval -#define scon sval -#define ieee u0.u0ieee -#define sbig u0.u0sbig - -struct Reloc -{ - int32 off; - uchar siz; - uchar done; - int16 type; - int32 add; - int32 xadd; - Sym* sym; - Sym* xsym; -}; - -struct Prog -{ - Adr from; - Adr to; - union - { - int32 u0regused; - Prog* u0forwd; - } u0; - Prog* cond; - Prog* link; - Prog* pcrel; - int32 pc; - int32 line; - int32 spadj; - uchar mark; - uchar optab; - uchar as; - uchar scond; - uchar reg; - uchar align; // unused -}; - -#define regused u0.u0regused -#define forwd u0.u0forwd -#define datasize reg -#define textflag reg - -#define iscall(p) ((p)->as == ABL) - -struct Sym -{ - char* name; - char* extname; // name used in external object files - short type; - short version; - uchar dupok; - uchar reachable; - uchar cgoexport; - uchar leaf; - int32 dynid; - int32 plt; - int32 got; - int32 value; - int32 sig; - int32 size; - int32 align; // if non-zero, required alignment in bytes - int32 elfsym; - int32 locals; // size of stack frame locals area - int32 args; // size of stack frame incoming arguments area - uchar special; - uchar fnptr; // used as fn ptr - uchar stkcheck; - uchar hide; - Sym* hash; // in hash table - Sym* allsym; // in all symbol list - Sym* next; // in text or data list - Sym* sub; // in SSUB list - Sym* outer; // container of sub - Sym* gotype; - Sym* reachparent; - Sym* queue; - char* file; - char* dynimplib; - char* dynimpvers; - struct Section* sect; - struct Hist* hist; - - // STEXT - Auto* autom; - Prog* text; - - // SDATA, SBSS - uchar* p; - int32 np; - int32 maxp; - Reloc* r; - int32 nr; - int32 maxr; -}; +#define S ((LSym*)0) +#define TNAME (ctxt->cursym?ctxt->cursym->name:noname) #define SIGNINTERN (1729*325*1729) -struct Autom -{ - Sym* asym; - Auto* link; - int32 aoffset; - short type; - Sym* gotype; -}; -struct Optab -{ - char as; - uchar a1; - char a2; - uchar a3; - uchar type; - char size; - char param; - char flag; - uchar pcrelsiz; -}; -struct Oprang -{ - Optab* start; - Optab* stop; -}; +typedef struct Count Count; struct Count { int32 count; @@ -220,10 +68,17 @@ struct Count enum { - LFROM = 1<<0, - LTO = 1<<1, - LPOOL = 1<<2, - LPCREL = 1<<3, +/* mark flags */ + FOLL = 1<<0, + LABEL = 1<<1, + LEAF = 1<<2, + + STRINGSZ = 200, + MINSIZ = 64, + NENT = 100, + MAXIO = 8192, + MAXHIST = 40, /* limit of path elements for history symbols */ + MINLC = 4, C_NONE = 0, C_REG, @@ -260,7 +115,7 @@ enum C_HFOREG, C_SOREG, C_ROREG, - C_SROREG, /* both S and R */ + C_SROREG, /* both nil and R */ C_LOREG, C_PC, @@ -270,179 +125,45 @@ enum C_ADDR, /* reference to relocatable address */ C_GOK, - -/* mark flags */ - FOLL = 1<<0, - LABEL = 1<<1, - LEAF = 1<<2, - - STRINGSZ = 200, - MINSIZ = 64, - NENT = 100, - MAXIO = 8192, - MAXHIST = 40, /* limit of path elements for history symbols */ - MINLC = 4, }; #ifndef COFFCVT -EXTERN int32 HEADR; /* length of header */ -EXTERN int HEADTYPE; /* type of header */ -EXTERN int32 INITDAT; /* data location */ -EXTERN int32 INITRND; /* data round above text location */ -EXTERN int32 INITTEXT; /* text location */ -EXTERN char* INITENTRY; /* entry point */ EXTERN int32 autosize; -EXTERN Auto* curauto; -EXTERN Auto* curhist; -EXTERN Prog* curp; -EXTERN Sym* cursym; -EXTERN Sym* datap; +EXTERN LSym* datap; EXTERN int debug[128]; -EXTERN Sym* etextp; EXTERN char* noname; EXTERN Prog* lastp; EXTERN int32 lcsize; EXTERN char literal[32]; EXTERN int nerrors; EXTERN int32 instoffset; -EXTERN Opcross opcross[8]; -EXTERN Oprang oprange[ALAST]; -EXTERN char* outfile; -EXTERN int32 pc; -EXTERN uchar repop[ALAST]; -EXTERN char* interpreter; EXTERN char* rpath; EXTERN uint32 stroffset; EXTERN int32 symsize; -EXTERN Sym* textp; -EXTERN char xcmp[C_GOK+1][C_GOK+1]; -EXTERN Prog zprg; -EXTERN int dtype; -EXTERN int tlsoffset; EXTERN int armsize; -EXTERN int goarm; -EXTERN Sym* adrgotype; // type symbol on last Adr read -EXTERN Sym* fromgotype; // type symbol on last p->from read - -extern char* anames[]; -extern Optab optab[]; - -void addpool(Prog*, Adr*); -EXTERN Prog* blitrl; -EXTERN Prog* elitrl; -EXTERN int goarm; +#pragma varargck type "I" uint32* -void initdiv(void); -EXTERN Prog* prog_div; -EXTERN Prog* prog_divu; -EXTERN Prog* prog_mod; -EXTERN Prog* prog_modu; - -#pragma varargck type "A" int -#pragma varargck type "C" int -#pragma varargck type "D" Adr* -#pragma varargck type "I" uchar* -#pragma varargck type "N" Adr* -#pragma varargck type "P" Prog* -#pragma varargck type "S" char* -#pragma varargck type "Z" char* -#pragma varargck type "i" char* - -int Aconv(Fmt*); -int Cconv(Fmt*); -int Dconv(Fmt*); -int Iconv(Fmt*); -int Nconv(Fmt*); -int Oconv(Fmt*); -int Pconv(Fmt*); -int Sconv(Fmt*); -int aclass(Adr*); -void addhist(int32, int); -Prog* appendp(Prog*); +int Iconv(Fmt *fp); +void adddynlib(char *lib); +void adddynrel(LSym *s, Reloc *r); +void adddynrela(LSym *rel, LSym *s, Reloc *r); +void adddynsym(Link *ctxt, LSym *s); +int archreloc(Reloc *r, LSym *s, vlong *val); void asmb(void); -void asmout(Prog*, Optab*, int32*, Sym*); -int32 atolwhex(char*); -Prog* brloop(Prog*); -void buildop(void); -void buildrep(int, int); -void cflush(void); -int chipzero(Ieee*); -int chipfloat(Ieee*); -int cmp(int, int); -int compound(Prog*); -double cputime(void); -void diag(char*, ...); -void divsig(void); -void dodata(void); -void doprof1(void); -void doprof2(void); -int32 entryvalue(void); -void exchange(Prog*); -void follow(void); -void hputl(int); -int isnop(Prog*); +void cput(int32 c); +int elfreloc1(Reloc *r, vlong sectoff); +void elfsetupplt(void); +void hput(int32 l); void listinit(void); -Sym* lookup(char*, int); -void cput(int); -void hput(int32); -void lput(int32); -void lputb(int32); -void lputl(int32); -void* mysbrk(uint32); -void names(void); -void nocache(Prog*); -int ocmp(const void*, const void*); -int32 opirr(int); -Optab* oplook(Prog*); -int32 oprrr(int, int); -int32 olr(int32, int, int, int); -int32 olhr(int32, int, int, int); -int32 olrr(int, int, int, int); -int32 olhrr(int, int, int, int); -int32 osr(int, int, int32, int, int); -int32 oshr(int, int32, int, int); -int32 ofsr(int, int, int32, int, int, Prog*); -int32 osrr(int, int, int, int); -int32 oshrr(int, int, int, int); -int32 omvl(Prog*, Adr*, int); -void patch(void); -void prasm(Prog*); -void prepend(Prog*, Prog*); -Prog* prg(void); -int pseudo(Prog*); -int32 regoff(Adr*); -int relinv(int); -int32 rnd(int32, int32); -void softfloat(void); -void span(void); -void strnput(char*, int); -int32 symaddr(Sym*); -void undef(void); -void vputb(uint64); -void vputl(uint64); -void wputb(uint16); -void wput(int32); -void wputl(ushort w); -void xdefine(char*, int, int32); +void lput(int32 l); +int machoreloc1(Reloc *r, vlong sectoff); +void main(int argc, char *argv[]); void noops(void); -int32 immrot(uint32); -int32 immaddr(int32); -int32 opbra(int, int); -int brextra(Prog*); -int isbranch(Prog*); -void doelf(void); -void dozerostk(void); // used by -Z - -vlong addaddr(Sym *s, Sym *t); -vlong addsize(Sym *s, Sym *t); -vlong addstring(Sym *s, char *str); -vlong adduint16(Sym *s, uint16 v); -vlong adduint32(Sym *s, uint32 v); -vlong adduint64(Sym *s, uint64 v); -vlong adduint8(Sym *s, uint8 v); -vlong adduintxx(Sym *s, uint64 v, int wid); +void nopstat(char *f, Count *c); +int32 rnd(int32 v, int32 r); +void wput(int32 l); /* Native is little-endian */ #define LPUT(a) lputl(a) diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c index 7502a3b81..875fc3e6b 100644 --- a/src/cmd/5l/list.c +++ b/src/cmd/5l/list.c @@ -36,355 +36,10 @@ void listinit(void) { - - fmtinstall('A', Aconv); - fmtinstall('C', Cconv); - fmtinstall('D', Dconv); - fmtinstall('P', Pconv); - fmtinstall('S', Sconv); - fmtinstall('N', Nconv); - fmtinstall('O', Oconv); // C_type constants + listinit5(); fmtinstall('I', Iconv); } -void -prasm(Prog *p) -{ - print("%P\n", p); -} - -int -Pconv(Fmt *fp) -{ - Prog *p; - int a; - - p = va_arg(fp->args, Prog*); - curp = p; - a = p->as; - switch(a) { - default: - fmtprint(fp, "(%d)", p->line); - if(p->reg == NREG && p->as != AGLOBL) - fmtprint(fp, " %A%C %D,%D", - a, p->scond, &p->from, &p->to); - else - if(p->from.type != D_FREG) - fmtprint(fp, " %A%C %D,R%d,%D", - a, p->scond, &p->from, p->reg, &p->to); - else - fmtprint(fp, " %A%C %D,F%d,%D", - a, p->scond, &p->from, p->reg, &p->to); - break; - - case ASWPW: - case ASWPBU: - fmtprint(fp, "(%d) %A%C R%d,%D,%D", - p->line, a, p->scond, p->reg, &p->from, &p->to); - break; - - case ADATA: - case AINIT_: - case ADYNT_: - fmtprint(fp, "(%d) %A%C %D/%d,%D", - p->line, a, p->scond, &p->from, p->reg, &p->to); - break; - - case AWORD: - fmtprint(fp, "(%d) WORD %D", p->line, &p->to); - break; - - case ADWORD: - fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to); - break; - } - - if(p->spadj) - fmtprint(fp, " (spadj%+d)", p->spadj); - - return 0; -} - -int -Aconv(Fmt *fp) -{ - char *s; - int a; - - a = va_arg(fp->args, int); - s = "???"; - if(a >= AXXX && a < ALAST) - s = anames[a]; - return fmtstrcpy(fp, s); -} - -char* strcond[16] = -{ - ".EQ", - ".NE", - ".HS", - ".LO", - ".MI", - ".PL", - ".VS", - ".VC", - ".HI", - ".LS", - ".GE", - ".LT", - ".GT", - ".LE", - "", - ".NV" -}; - -int -Cconv(Fmt *fp) -{ - char s[20]; - int c; - - c = va_arg(fp->args, int); - strcpy(s, strcond[c & C_SCOND]); - if(c & C_SBIT) - strcat(s, ".S"); - if(c & C_PBIT) - strcat(s, ".P"); - if(c & C_WBIT) - strcat(s, ".W"); - if(c & C_UBIT) /* ambiguous with FBIT */ - strcat(s, ".U"); - return fmtstrcpy(fp, s); -} - -int -Dconv(Fmt *fp) -{ - char str[STRINGSZ]; - const char *op; - Adr *a; - int32 v; - - a = va_arg(fp->args, Adr*); - switch(a->type) { - - default: - snprint(str, sizeof str, "GOK-type(%d)", a->type); - break; - - case D_NONE: - str[0] = 0; - if(a->name != D_NONE || a->reg != NREG || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(NONE)", a, a->reg); - break; - - case D_CONST: - if(a->reg == NREG) - snprint(str, sizeof str, "$%N", a); - else - snprint(str, sizeof str, "$%N(R%d)", a, a->reg); - break; - - case D_CONST2: - snprint(str, sizeof str, "$%d-%d", a->offset, a->offset2); - break; - - case D_SHIFT: - v = a->offset; - op = &"<<>>->@>"[(((v>>5) & 3) << 1)]; - if(v & (1<<4)) - snprint(str, sizeof str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15); - else - snprint(str, sizeof str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31); - if(a->reg != NREG) - seprint(str+strlen(str), str+sizeof str, "(R%d)", a->reg); - break; - - case D_OCONST: - snprint(str, sizeof str, "$*$%N", a); - if(a->reg != NREG) - snprint(str, sizeof str, "%N(R%d)(CONST)", a, a->reg); - break; - - case D_OREG: - if(a->reg != NREG) - snprint(str, sizeof str, "%N(R%d)", a, a->reg); - else - snprint(str, sizeof str, "%N", a); - break; - - case D_REG: - snprint(str, sizeof str, "R%d", a->reg); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_REGREG: - snprint(str, sizeof str, "(R%d,R%d)", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_REGREG2: - snprint(str, sizeof str, "R%d,R%d", a->reg, (int)a->offset); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_FREG: - snprint(str, sizeof str, "F%d", a->reg); - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(R%d)(REG)", a, a->reg); - break; - - case D_PSR: - switch(a->reg) { - case 0: - snprint(str, sizeof str, "CPSR"); - break; - case 1: - snprint(str, sizeof str, "SPSR"); - break; - default: - snprint(str, sizeof str, "PSR%d", a->reg); - break; - } - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(PSR%d)(REG)", a, a->reg); - break; - - case D_FPCR: - switch(a->reg){ - case 0: - snprint(str, sizeof str, "FPSR"); - break; - case 1: - snprint(str, sizeof str, "FPCR"); - break; - default: - snprint(str, sizeof str, "FCR%d", a->reg); - break; - } - if(a->name != D_NONE || a->sym != S) - snprint(str, sizeof str, "%N(FCR%d)(REG)", a, a->reg); - - break; - - case D_BRANCH: /* botch */ - if(curp->cond != P) { - v = curp->cond->pc; - if(a->sym != S) - snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v); - else - snprint(str, sizeof str, "%.5ux(BRANCH)", v); - } else - if(a->sym != S) - snprint(str, sizeof str, "%s+%d(APC)", a->sym->name, a->offset); - else - snprint(str, sizeof str, "%d(APC)", a->offset); - break; - - case D_FCONST: - snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee)); - break; - - case D_SCONST: - snprint(str, sizeof str, "$\"%S\"", a->sval); - break; - } - return fmtstrcpy(fp, str); -} - -int -Nconv(Fmt *fp) -{ - char str[STRINGSZ]; - Adr *a; - Sym *s; - - a = va_arg(fp->args, Adr*); - s = a->sym; - switch(a->name) { - default: - sprint(str, "GOK-name(%d)", a->name); - break; - - case D_NONE: - sprint(str, "%d", a->offset); - break; - - case D_EXTERN: - if(s == S) - sprint(str, "%d(SB)", a->offset); - else - sprint(str, "%s+%d(SB)", s->name, a->offset); - break; - - case D_STATIC: - if(s == S) - sprint(str, "<>+%d(SB)", a->offset); - else - sprint(str, "%s<>+%d(SB)", s->name, a->offset); - break; - - case D_AUTO: - if(s == S) - sprint(str, "%d(SP)", a->offset); - else - sprint(str, "%s-%d(SP)", s->name, -a->offset); - break; - - case D_PARAM: - if(s == S) - sprint(str, "%d(FP)", a->offset); - else - sprint(str, "%s+%d(FP)", s->name, a->offset); - break; - } - return fmtstrcpy(fp, str); -} - -int -Sconv(Fmt *fp) -{ - int i, c; - char str[STRINGSZ], *p, *a; - - a = va_arg(fp->args, char*); - p = str; - for(i=0; i<sizeof(int32); i++) { - c = a[i] & 0xff; - if(c >= 'a' && c <= 'z' || - c >= 'A' && c <= 'Z' || - c >= '0' && c <= '9' || - c == ' ' || c == '%') { - *p++ = c; - continue; - } - *p++ = '\\'; - switch(c) { - case 0: - *p++ = 'z'; - continue; - case '\\': - case '"': - *p++ = c; - continue; - case '\n': - *p++ = 'n'; - continue; - case '\t': - *p++ = 't'; - continue; - } - *p++ = (c>>6) + '0'; - *p++ = ((c>>3) & 7) + '0'; - *p++ = (c & 7) + '0'; - } - *p = 0; - return fmtstrcpy(fp, str); -} - int Iconv(Fmt *fp) { @@ -413,83 +68,3 @@ Iconv(Fmt *fp) free(s); return 0; } - -static char* -cnames[] = -{ - [C_ADDR] = "C_ADDR", - [C_FAUTO] = "C_FAUTO", - [C_ZFCON] = "C_SFCON", - [C_SFCON] = "C_SFCON", - [C_LFCON] = "C_LFCON", - [C_FCR] = "C_FCR", - [C_FOREG] = "C_FOREG", - [C_FREG] = "C_FREG", - [C_GOK] = "C_GOK", - [C_HAUTO] = "C_HAUTO", - [C_HFAUTO] = "C_HFAUTO", - [C_HFOREG] = "C_HFOREG", - [C_HOREG] = "C_HOREG", - [C_HREG] = "C_HREG", - [C_LACON] = "C_LACON", - [C_LAUTO] = "C_LAUTO", - [C_LBRA] = "C_LBRA", - [C_LCON] = "C_LCON", - [C_LCONADDR] = "C_LCONADDR", - [C_LOREG] = "C_LOREG", - [C_NCON] = "C_NCON", - [C_NONE] = "C_NONE", - [C_PC] = "C_PC", - [C_PSR] = "C_PSR", - [C_RACON] = "C_RACON", - [C_RCON] = "C_RCON", - [C_REG] = "C_REG", - [C_REGREG] = "C_REGREG", - [C_REGREG2] = "C_REGREG2", - [C_ROREG] = "C_ROREG", - [C_SAUTO] = "C_SAUTO", - [C_SBRA] = "C_SBRA", - [C_SCON] = "C_SCON", - [C_SHIFT] = "C_SHIFT", - [C_SOREG] = "C_SOREG", - [C_SP] = "C_SP", - [C_SROREG] = "C_SROREG" -}; - -int -Oconv(Fmt *fp) -{ - char buf[500]; - int o; - - o = va_arg(fp->args, int); - if(o < 0 || o >= nelem(cnames) || cnames[o] == nil) { - snprint(buf, sizeof(buf), "C_%d", o); - return fmtstrcpy(fp, buf); - } - return fmtstrcpy(fp, cnames[o]); -} - -void -diag(char *fmt, ...) -{ - char buf[1024], *tn, *sep; - va_list arg; - - tn = ""; - sep = ""; - if(cursym != S) { - tn = cursym->name; - sep = ": "; - } - va_start(arg, fmt); - vseprint(buf, buf+sizeof(buf), fmt, arg); - va_end(arg); - print("%s%s%s\n", tn, sep, buf); - - nerrors++; - if(nerrors > 20) { - print("too many errors\n"); - errorexit(); - } -} diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c index 305ed684e..d42c86289 100644 --- a/src/cmd/5l/noop.c +++ b/src/cmd/5l/noop.c @@ -32,677 +32,12 @@ #include "l.h" #include "../ld/lib.h" -#include "../../pkg/runtime/stack.h" - -static Sym* sym_div; -static Sym* sym_divu; -static Sym* sym_mod; -static Sym* sym_modu; -static Sym* symmorestack; -static Prog* pmorestack; - -static Prog* stacksplit(Prog*, int32); - -static void -linkcase(Prog *casep) -{ - Prog *p; - - for(p = casep; p != P; p = p->link){ - if(p->as == ABCASE) { - for(; p != P && p->as == ABCASE; p = p->link) - p->pcrel = casep; - break; - } - } -} void noops(void) { - Prog *p, *q, *q1, *q2; - int o; - Sym *tlsfallback, *gmsym; - - /* - * find leaf subroutines - * strip NOPs - * expand RET - * expand BECOME pseudo - * fixup TLS - */ - - if(debug['v']) - Bprint(&bso, "%5.2f noops\n", cputime()); - Bflush(&bso); - - symmorestack = lookup("runtime.morestack", 0); - if(symmorestack->type != STEXT) { - diag("runtime·morestack not defined"); - errorexit(); - } - pmorestack = symmorestack->text; - pmorestack->reg |= NOSPLIT; - - tlsfallback = lookup("runtime.read_tls_fallback", 0); - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - q = P; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case ACASE: - if(flag_shared) - linkcase(p); - break; - - case ATEXT: - p->mark |= LEAF; - break; - - case ARET: - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - q = p; - if(prog_div == P) - initdiv(); - cursym->text->mark &= ~LEAF; - continue; - - case ANOP: - q1 = p->link; - q->link = q1; /* q is non-nop */ - if(q1 != P) - q1->mark |= p->mark; - continue; - - case ABL: - case ABX: - cursym->text->mark &= ~LEAF; - - case ABCASE: - case AB: - - case ABEQ: - case ABNE: - case ABCS: - case ABHS: - case ABCC: - case ABLO: - case ABMI: - case ABPL: - case ABVS: - case ABVC: - case ABHI: - case ABLS: - case ABGE: - case ABLT: - case ABGT: - case ABLE: - q1 = p->cond; - if(q1 != P) { - while(q1->as == ANOP) { - q1 = q1->link; - p->cond = q1; - } - } - break; - case AWORD: - // Rewrite TLS register fetch: MRC 15, 0, <reg>, C13, C0, 3 - if((p->to.offset & 0xffff0fff) == 0xee1d0f70) { - if(HEADTYPE == Hopenbsd) { - p->as = ARET; - } else if(goarm < 7) { - if(tlsfallback->type != STEXT) { - diag("runtime·read_tls_fallback not defined"); - errorexit(); - } - // BL runtime.read_tls_fallback(SB) - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = tlsfallback; - p->cond = tlsfallback->text; - p->to.offset = 0; - cursym->text->mark &= ~LEAF; - } - if(linkmode == LinkExternal) { - // runtime.tlsgm is relocated with R_ARM_TLS_LE32 - // and $runtime.tlsgm will contain the TLS offset. - // - // MOV $runtime.tlsgm+tlsoffset(SB), REGTMP - // ADD REGTMP, <reg> - // - // In shared mode, runtime.tlsgm is relocated with - // R_ARM_TLS_IE32 and runtime.tlsgm(SB) will point - // to the GOT entry containing the TLS offset. - // - // MOV runtime.tlsgm(SB), REGTMP - // ADD REGTMP, <reg> - // SUB -tlsoffset, <reg> - // - // The SUB compensates for tlsoffset - // used in runtime.save_gm and runtime.load_gm. - q = p; - p = appendp(p); - p->as = AMOVW; - p->scond = 14; - p->reg = NREG; - if(flag_shared) { - p->from.type = D_OREG; - p->from.offset = 0; - } else { - p->from.type = D_CONST; - p->from.offset = tlsoffset; - } - p->from.sym = gmsym; - p->from.name = D_EXTERN; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - p = appendp(p); - p->as = AADD; - p->scond = 14; - p->reg = NREG; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - - if(flag_shared) { - p = appendp(p); - p->as = ASUB; - p->scond = 14; - p->reg = NREG; - p->from.type = D_CONST; - p->from.offset = -tlsoffset; - p->to.type = D_REG; - p->to.reg = (q->to.offset & 0xf000) >> 12; - p->to.offset = 0; - } - } - } - } - q = p; - } - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - o = p->as; - switch(o) { - case ATEXT: - autosize = p->to.offset + 4; - if(autosize <= 4) - if(cursym->text->mark & LEAF) { - p->to.offset = -4; - autosize = 0; - } - - if(!autosize && !(cursym->text->mark & LEAF)) { - if(debug['v']) - Bprint(&bso, "save suppressed in: %s\n", - cursym->name); - Bflush(&bso); - cursym->text->mark |= LEAF; - } - if(cursym->text->mark & LEAF) { - cursym->leaf = 1; - if(!autosize) - break; - } - - if(!(p->reg & NOSPLIT)) - p = stacksplit(p, autosize); // emit split check - - // MOVW.W R14,$-autosize(SP) - p = appendp(p); - p->as = AMOVW; - p->scond |= C_WBIT; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_OREG; - p->to.offset = -autosize; - p->to.reg = REGSP; - p->spadj = autosize; - - if(cursym->text->reg & WRAPPER) { - // g->panicwrap += autosize; - // MOVW panicwrap_offset(g), R3 - // ADD $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - } - break; - - case ARET: - nocache(p); - if(cursym->text->mark & LEAF) { - if(!autosize) { - p->as = AB; - p->from = zprg.from; - if(p->to.sym) { // retjmp - p->to.type = D_BRANCH; - p->cond = p->to.sym->text; - } else { - p->to.type = D_OREG; - p->to.offset = 0; - p->to.reg = REGLINK; - } - break; - } - } - - if(cursym->text->reg & WRAPPER) { - int cond; - - // Preserve original RET's cond, to allow RET.EQ - // in the implementation of reflect.call. - cond = p->scond; - p->scond = C_SCOND_NONE; - - // g->panicwrap -= autosize; - // MOVW panicwrap_offset(g), R3 - // SUB $autosize, R3 - // MOVW R3 panicwrap_offset(g) - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->from.offset = 2*PtrSize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = ASUB; - p->from.type = D_CONST; - p->from.offset = autosize; - p->to.type = D_REG; - p->to.reg = 3; - p = appendp(p); - - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = REGG; - p->to.offset = 2*PtrSize; - p = appendp(p); - - p->scond = cond; - } - - p->as = AMOVW; - p->scond |= C_PBIT; - p->from.type = D_OREG; - p->from.offset = autosize; - p->from.reg = REGSP; - p->to.type = D_REG; - p->to.reg = REGPC; - // If there are instructions following - // this ARET, they come from a branch - // with the same stackframe, so no spadj. - - if(p->to.sym) { // retjmp - p->to.reg = REGLINK; - q2 = appendp(p); - q2->as = AB; - q2->to.type = D_BRANCH; - q2->to.sym = p->to.sym; - q2->cond = p->to.sym->text; - p->to.sym = nil; - p = q2; - } - break; - - case AADD: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - - case ASUB: - if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = p->from.offset; - break; - - case ADIV: - case ADIVU: - case AMOD: - case AMODU: - if(debug['M']) - break; - if(p->from.type != D_REG) - break; - if(p->to.type != D_REG) - break; - q1 = p; - - /* MOV a,4(SP) */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->from.reg; - p->to.type = D_OREG; - p->to.reg = REGSP; - p->to.offset = 4; - - /* MOV b,REGTMP */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = q1->reg; - if(q1->reg == NREG) - p->from.reg = q1->to.reg; - p->to.type = D_REG; - p->to.reg = REGTMP; - p->to.offset = 0; - - /* CALL appropriate */ - p = appendp(p); - p->as = ABL; - p->line = q1->line; - p->to.type = D_BRANCH; - p->cond = p; - switch(o) { - case ADIV: - p->cond = prog_div; - p->to.sym = sym_div; - break; - case ADIVU: - p->cond = prog_divu; - p->to.sym = sym_divu; - break; - case AMOD: - p->cond = prog_mod; - p->to.sym = sym_mod; - break; - case AMODU: - p->cond = prog_modu; - p->to.sym = sym_modu; - break; - } + LSym *s; - /* MOV REGTMP, b */ - p = appendp(p); - p->as = AMOVW; - p->line = q1->line; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = q1->to.reg; - - /* ADD $8,SP */ - p = appendp(p); - p->as = AADD; - p->line = q1->line; - p->from.type = D_CONST; - p->from.reg = NREG; - p->from.offset = 8; - p->reg = NREG; - p->to.type = D_REG; - p->to.reg = REGSP; - p->spadj = -8; - - /* Keep saved LR at 0(SP) after SP change. */ - /* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */ - /* TODO: Remove SP adjustments; see issue 6699. */ - q1->as = AMOVW; - q1->from.type = D_OREG; - q1->from.reg = REGSP; - q1->from.offset = 0; - q1->reg = NREG; - q1->to.type = D_REG; - q1->to.reg = REGTMP; - - /* SUB $8,SP */ - q1 = appendp(q1); - q1->as = AMOVW; - q1->from.type = D_REG; - q1->from.reg = REGTMP; - q1->reg = NREG; - q1->to.type = D_OREG; - q1->to.reg = REGSP; - q1->to.offset = -8; - q1->scond |= C_WBIT; - q1->spadj = 8; - - break; - case AMOVW: - if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP) - p->spadj = -p->to.offset; - if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC) - p->spadj = -p->from.offset; - if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP) - p->spadj = -p->from.offset; - break; - } - } - } -} - -static Prog* -stacksplit(Prog *p, int32 framesize) -{ - int32 arg; - - // MOVW g_stackguard(g), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_OREG; - p->from.reg = REGG; - p->to.type = D_REG; - p->to.reg = 1; - - if(framesize <= StackSmall) { - // small stack: SP < stackguard - // CMP stackguard, SP - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = REGSP; - } else if(framesize <= StackBig) { - // large stack: SP-framesize < stackguard-StackSmall - // MOVW $-framesize(SP), R2 - // CMP stackguard, R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = -framesize; - p->to.type = D_REG; - p->to.reg = 2; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - } else { - // Such a large stack we need to protect against wraparound - // if SP is close to zero. - // SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall) - // The +StackGuard on both sides is required to keep the left side positive: - // SP is allowed to be slightly below stackguard. See stack.h. - // CMP $StackPreempt, R1 - // MOVW.NE $StackGuard(SP), R2 - // SUB.NE R1, R2 - // MOVW.NE $(framesize+(StackGuard-StackSmall)), R3 - // CMP.NE R3, R2 - p = appendp(p); - p->as = ACMP; - p->from.type = D_CONST; - p->from.offset = (uint32)StackPreempt; - p->reg = 1; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = REGSP; - p->from.offset = StackGuard; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ASUB; - p->from.type = D_REG; - p->from.reg = 1; - p->to.type = D_REG; - p->to.reg = 2; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = framesize + (StackGuard - StackSmall); - p->to.type = D_REG; - p->to.reg = 3; - p->scond = C_SCOND_NE; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 3; - p->reg = 2; - p->scond = C_SCOND_NE; - } - - // MOVW.LS $framesize, R1 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - p->from.offset = framesize; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW.LS $args, R2 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_CONST; - arg = cursym->text->to.offset2; - if(arg == 1) // special marker for known 0 - arg = 0; - if(arg&3) - diag("misaligned argument size in stack split"); - p->from.offset = arg; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW.LS R14, R3 - p = appendp(p); - p->as = AMOVW; - p->scond = C_SCOND_LS; - p->from.type = D_REG; - p->from.reg = REGLINK; - p->to.type = D_REG; - p->to.reg = 3; - - // BL.LS runtime.morestack(SB) // modifies LR, returns with LO still asserted - p = appendp(p); - p->as = ABL; - p->scond = C_SCOND_LS; - p->to.type = D_BRANCH; - p->to.sym = symmorestack; - p->cond = pmorestack; - - // BLS start - p = appendp(p); - p->as = ABLS; - p->to.type = D_BRANCH; - p->cond = cursym->text->link; - - return p; -} - -static void -sigdiv(char *n) -{ - Sym *s; - - s = lookup(n, 0); - if(s->type == STEXT) - if(s->sig == 0) - s->sig = SIGNINTERN; -} - -void -divsig(void) -{ - sigdiv("_div"); - sigdiv("_divu"); - sigdiv("_mod"); - sigdiv("_modu"); -} - -void -initdiv(void) -{ - Sym *s2, *s3, *s4, *s5; - - if(prog_div != P) - return; - sym_div = s2 = lookup("_div", 0); - sym_divu = s3 = lookup("_divu", 0); - sym_mod = s4 = lookup("_mod", 0); - sym_modu = s5 = lookup("_modu", 0); - prog_div = s2->text; - prog_divu = s3->text; - prog_mod = s4->text; - prog_modu = s5->text; - if(prog_div == P) { - diag("undefined: %s", s2->name); - prog_div = cursym->text; - } - if(prog_divu == P) { - diag("undefined: %s", s3->name); - prog_divu = cursym->text; - } - if(prog_mod == P) { - diag("undefined: %s", s4->name); - prog_mod = cursym->text; - } - if(prog_modu == P) { - diag("undefined: %s", s5->name); - prog_modu = cursym->text; - } -} - -void -nocache(Prog *p) -{ - p->optab = 0; - p->from.class = 0; - p->to.class = 0; + for(s = ctxt->textp; s != nil; s = s->next) + ctxt->arch->addstacksplit(ctxt, s); } diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c index 80f5787dc..86a0ece2e 100644 --- a/src/cmd/5l/obj.c +++ b/src/cmd/5l/obj.c @@ -30,120 +30,24 @@ // Reading object files. -#define EXTERN #include "l.h" #include "../ld/lib.h" #include "../ld/elf.h" #include "../ld/dwarf.h" #include <ar.h> -#ifndef DEFAULT -#define DEFAULT '9' -#endif - -char *noname = "<none>"; -char *thestring = "arm"; - -Header headers[] = { - "noheader", Hnoheader, - "risc", Hrisc, - "plan9", Hplan9x32, - "ixp1200", Hixp1200, - "ipaq", Hipaq, - "linux", Hlinux, - "freebsd", Hfreebsd, - "netbsd", Hnetbsd, - 0, 0 -}; - -/* - * -Hrisc -T0x10005000 -R4 is aif for risc os - * -Hplan9 -T4128 -R4096 is plan9 format - * -Hixp1200 is IXP1200 (raw) - * -Hipaq -T0xC0008010 -R1024 is ipaq - * -Hlinux -Tx -Rx is linux elf - * -Hfreebsd is freebsd elf - * -Hnetbsd is netbsd elf - */ +char *thestring = "arm"; +LinkArch *thelinkarch = &linkarm; void -main(int argc, char *argv[]) +linkarchinit(void) { - char *p; - Sym *s; - - Binit(&bso, 1, OWRITE); - listinit(); - nerrors = 0; - outfile = "5.out"; - HEADTYPE = -1; - INITTEXT = -1; - INITDAT = -1; - INITRND = -1; - INITENTRY = 0; - linkmode = LinkAuto; - nuxiinit(); - - p = getgoarm(); - if(p != nil) - goarm = atoi(p); - else - goarm = 6; - if(goarm == 5) - debug['F'] = 1; - - flagcount("1", "use alternate profiling code", &debug['1']); - flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); - flagstr("E", "sym: entry symbol", &INITENTRY); - flagint32("D", "addr: data address", &INITDAT); - flagcount("G", "debug pseudo-ops", &debug['G']); - flagfn1("I", "interp: set ELF interp", setinterp); - flagfn1("L", "dir: add dir to library path", Lflag); - flagfn1("H", "head: header type", setheadtype); - flagcount("K", "add stack underflow checks", &debug['K']); - flagcount("M", "disable software div/mod", &debug['M']); - flagcount("O", "print pc-line tables", &debug['O']); - flagcount("P", "debug code generation", &debug['P']); - flagint32("R", "rnd: address rounding", &INITRND); - flagint32("T", "addr: text address", &INITTEXT); - flagfn0("V", "print version and exit", doversion); - flagcount("W", "disassemble input", &debug['W']); - flagfn2("X", "name value: define string data", addstrdata); - flagcount("Z", "clear stack frame on entry", &debug['Z']); - flagcount("a", "disassemble output", &debug['a']); - flagcount("c", "dump call graph", &debug['c']); - flagcount("d", "disable dynamic executable", &debug['d']); - flagstr("extld", "linker to run in external mode", &extld); - flagstr("extldflags", "flags for external linker", &extldflags); - flagcount("f", "ignore version mismatch", &debug['f']); - flagcount("g", "disable go package data checks", &debug['g']); - flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix); - flagstr("k", "sym: set field tracking symbol", &tracksym); - flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode); - flagcount("n", "dump symbol table", &debug['n']); - flagstr("o", "outfile: set output file", &outfile); - flagcount("p", "insert profiling code", &debug['p']); - flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath); - flagcount("race", "enable race detector", &flag_race); - flagcount("s", "disable symbol table", &debug['s']); - flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared); - flagstr("tmpdir", "leave temporary files in this directory", &tmpdir); - flagcount("u", "reject unsafe packages", &debug['u']); - flagcount("v", "print link trace", &debug['v']); - flagcount("w", "disable DWARF generation", &debug['w']); - - flagparse(&argc, &argv, usage); - - if(argc != 1) - usage(); - - if(flag_shared) - linkmode = LinkExternal; - - mywhatsys(); +} - if(HEADTYPE == -1) - HEADTYPE = headtype(goos); +void +archinit(void) +{ + LSym *s; // getgoextlinkenabled is based on GO_EXTLINK_ENABLED when // Go was built; see ../../make.bash. @@ -158,34 +62,15 @@ main(int argc, char *argv[]) sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE)); break; case Hlinux: + case Hfreebsd: break; } - libinit(); - switch(HEADTYPE) { default: diag("unknown -H option"); errorexit(); - case Hnoheader: /* no header */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hrisc: /* aif for risc os */ - HEADR = 128L; - if(INITTEXT == -1) - INITTEXT = 0x10005000 + HEADR; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hplan9x32: /* plan 9 */ + case Hplan9: /* plan 9 */ HEADR = 32L; if(INITTEXT == -1) INITTEXT = 4128; @@ -194,30 +79,11 @@ main(int argc, char *argv[]) if(INITRND == -1) INITRND = 4096; break; - case Hixp1200: /* boot for IXP1200 */ - HEADR = 0L; - if(INITTEXT == -1) - INITTEXT = 0x0; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 4; - break; - case Hipaq: /* boot for ipaq */ - HEADR = 16L; - if(INITTEXT == -1) - INITTEXT = 0xC0008010; - if(INITDAT == -1) - INITDAT = 0; - if(INITRND == -1) - INITRND = 1024; - break; case Hlinux: /* arm elf */ case Hfreebsd: case Hnetbsd: + case Hnacl: debug['d'] = 0; // with dynamic linking - tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m - // this number is known to ../../pkg/runtime/rt0_*_arm.s elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -231,578 +97,9 @@ main(int argc, char *argv[]) if(INITDAT != 0 && INITRND != 0) print("warning: -D0x%ux is ignored because of -R0x%ux\n", INITDAT, INITRND); - if(debug['v']) - Bprint(&bso, "HEADER = -H0x%d -T0x%ux -D0x%ux -R0x%ux\n", - HEADTYPE, INITTEXT, INITDAT, INITRND); - Bflush(&bso); - zprg.as = AGOK; - zprg.scond = 14; - zprg.reg = NREG; - zprg.from.name = D_NONE; - zprg.from.type = D_NONE; - zprg.from.reg = NREG; - zprg.to = zprg.from; - buildop(); - histgen = 0; - pc = 0; - dtype = 4; - - version = 0; - cbp = buf.cbuf; - cbc = sizeof(buf.cbuf); // embed goarm to runtime.goarm - s = lookup("runtime.goarm", 0); - s->dupok = 1; - adduint8(s, goarm); - - addlibpath("command line", "command line", argv[0], "main"); - loadlib(); - - // mark some functions that are only referenced after linker code editing - if(debug['F']) - mark(rlookup("_sfloat", 0)); - mark(lookup("runtime.read_tls_fallback", 0)); - deadcode(); - if(textp == nil) { - diag("no code"); - errorexit(); - } - - patch(); - if(debug['p']) - if(debug['1']) - doprof1(); - else - doprof2(); - doelf(); - follow(); - softfloat(); - // 5l -Z means zero the stack frame on entry. - // This slows down function calls but can help avoid - // false positives in garbage collection. - if(debug['Z']) - dozerostk(); - noops(); // generate stack split prolog, handle div/mod, etc. - dostkcheck(); - span(); - addexport(); - // textaddress() functionality is handled in span() - pclntab(); - symtab(); - dodata(); - address(); - doweak(); - reloc(); - asmb(); - undef(); - hostlink(); - - if(debug['c']) - print("ARM size = %d\n", armsize); - if(debug['v']) { - Bprint(&bso, "%5.2f cpu time\n", cputime()); - Bprint(&bso, "%d sizeof adr\n", sizeof(Adr)); - Bprint(&bso, "%d sizeof prog\n", sizeof(Prog)); - } - Bflush(&bso); - errorexit(); -} - -static Sym* -zsym(char *pn, Biobuf *f, Sym *h[]) -{ - int o; - - o = BGETC(f); - if(o == 0) - return S; - if(o < 0 || o >= NSYM || h[o] == nil) - mangle(pn); - return h[o]; -} - -static void -zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[]) -{ - int i, c; - int32 l; - Sym *s; - Auto *u; - - a->type = BGETC(f); - a->reg = BGETC(f); - c = BGETC(f); - if(c < 0 || c > NSYM){ - print("sym out of range: %d\n", c); - BPUTC(f, ALAST+1); - return; - } - a->sym = h[c]; - a->name = BGETC(f); - adrgotype = zsym(pn, f, h); - - if((schar)a->reg < 0 || a->reg > NREG) { - print("register out of range %d\n", a->reg); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - } - - if(a->type == D_CONST || a->type == D_OCONST) { - if(a->name == D_EXTERN || a->name == D_STATIC) { - s = a->sym; - if(s != S && (s->type == STEXT || s->type == SCONST || s->type == SXREF)) { - if(0 && !s->fnptr && s->name[0] != '.') - print("%s used as function pointer\n", s->name); - s->fnptr = 1; // over the top cos of SXREF - } - } - } - - switch(a->type) { - default: - print("unknown type %d\n", a->type); - BPUTC(f, ALAST+1); - return; /* force real diagnostic */ - - case D_NONE: - case D_REG: - case D_FREG: - case D_PSR: - case D_FPCR: - break; - - case D_REGREG: - case D_REGREG2: - a->offset = BGETC(f); - break; - - case D_CONST2: - a->offset2 = BGETLE4(f); // fall through - case D_BRANCH: - case D_OREG: - case D_CONST: - case D_OCONST: - case D_SHIFT: - a->offset = BGETLE4(f); - break; - - case D_SCONST: - a->sval = mal(NSNAME); - Bread(f, a->sval, NSNAME); - break; - - case D_FCONST: - a->ieee.l = BGETLE4(f); - a->ieee.h = BGETLE4(f); - break; - } - s = a->sym; - if(s == S) - return; - i = a->name; - if(i != D_AUTO && i != D_PARAM) { - if(s && adrgotype) - s->gotype = adrgotype; - return; - } - - l = a->offset; - for(u=curauto; u; u=u->link) - if(u->asym == s) - if(u->type == i) { - if(u->aoffset > l) - u->aoffset = l; - if(adrgotype) - u->gotype = adrgotype; - return; - } - - u = mal(sizeof(Auto)); - u->link = curauto; - curauto = u; - u->asym = s; - u->aoffset = l; - u->type = i; - u->gotype = adrgotype; -} - -void -nopout(Prog *p) -{ - p->as = ANOP; - p->from.type = D_NONE; - p->to.type = D_NONE; -} - -void -ldobj1(Biobuf *f, char *pkg, int64 len, char *pn) -{ - int32 ipc; - Prog *p; - Sym *h[NSYM], *s; - int v, o, r, skip; - uint32 sig; - char *name; - int ntext; - int32 eof; - char src[1024], *x; - Prog *lastp; - - lastp = nil; - ntext = 0; - eof = Boffset(f) + len; - src[0] = 0; - pn = estrdup(pn); // we keep it in Sym* references - -newloop: - memset(h, 0, sizeof(h)); - version++; - histfrogp = 0; - ipc = pc; - skip = 0; - -loop: - if(f->state == Bracteof || Boffset(f) >= eof) - goto eof; - o = BGETC(f); - if(o == Beof) - goto eof; - - if(o <= AXXX || o >= ALAST) { - diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o); - print(" probably not a .5 file\n"); - errorexit(); - } - if(o == ANAME || o == ASIGNAME) { - sig = 0; - if(o == ASIGNAME) - sig = BGETLE4(f); - v = BGETC(f); /* type */ - o = BGETC(f); /* sym */ - r = 0; - if(v == D_STATIC) - r = version; - name = Brdline(f, '\0'); - if(name == nil) { - if(Blinelen(f) > 0) { - fprint(2, "%s: name too long\n", pn); - errorexit(); - } - goto eof; - } - x = expandpkg(name, pkg); - s = lookup(x, r); - if(x != name) - free(x); - - if(sig != 0){ - if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures %ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); - s->sig = sig; - s->file = pn; - } - - if(debug['W']) - print(" ANAME %s\n", s->name); - if(o < 0 || o >= nelem(h)) { - fprint(2, "%s: mangled input file\n", pn); - errorexit(); - } - h[o] = s; - if((v == D_EXTERN || v == D_STATIC) && s->type == 0) - s->type = SXREF; - if(v == D_FILE) { - if(s->type != SFILE) { - histgen++; - s->type = SFILE; - s->value = histgen; - } - if(histfrogp < MAXHIST) { - histfrog[histfrogp] = s; - histfrogp++; - } else - collapsefrog(s); - dwarfaddfrag(s->value, s->name); - } - goto loop; - } - - p = mal(sizeof(Prog)); - p->as = o; - p->scond = BGETC(f); - p->reg = BGETC(f); - p->line = BGETLE4(f); - - zaddr(pn, f, &p->from, h); - fromgotype = adrgotype; - zaddr(pn, f, &p->to, h); - - if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG) - diag("register out of range %A %d", p->as, p->reg); - - p->link = P; - p->cond = P; - - if(debug['W']) - print("%P\n", p); - - switch(o) { - case AHISTORY: - if(p->to.offset == -1) { - addlib(src, pn); - histfrogp = 0; - goto loop; - } - if(src[0] == '\0') - copyhistfrog(src, sizeof src); - addhist(p->line, D_FILE); /* 'z' */ - if(p->to.offset) - addhist(p->to.offset, D_FILE1); /* 'Z' */ - savehist(p->line, p->to.offset); - histfrogp = 0; - goto loop; - - case AEND: - histtoauto(); - if(cursym != nil && cursym->text) - cursym->autom = curauto; - curauto = 0; - cursym = nil; - if(Boffset(f) == eof) - return; - goto newloop; - - case AGLOBL: - s = p->from.sym; - if(s == S) { - diag("GLOBL must have a name\n%P", p); - errorexit(); - } - if(s->type == 0 || s->type == SXREF) { - s->type = SBSS; - s->value = 0; - } - if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { - diag("redefinition: %s\n%P", s->name, p); - s->type = SBSS; - s->value = 0; - } - if(p->to.offset > s->size) - s->size = p->to.offset; - if(p->reg & DUPOK) - s->dupok = 1; - if(p->reg & RODATA) - s->type = SRODATA; - else if(p->reg & NOPTR) - s->type = SNOPTRBSS; - break; - - case ADATA: - // Assume that AGLOBL comes after ADATA. - // If we've seen an AGLOBL that said this sym was DUPOK, - // ignore any more ADATA we see, which must be - // redefinitions. - s = p->from.sym; - if(s->dupok) { -// if(debug['v']) -// Bprint(&bso, "skipping %s in %s: dupok\n", s->name, pn); - goto loop; - } - if(s->file == nil) - s->file = pn; - else if(s->file != pn) { - diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn); - errorexit(); - } - savedata(s, p, pn); - unmal(p, sizeof *p); - break; - - case AGOK: - diag("unknown opcode\n%P", p); - p->pc = pc; - pc++; - break; - - case ATYPE: - if(skip) - goto casedef; - pc++; - goto loop; - - case ATEXT: - if(cursym != nil && cursym->text) { - histtoauto(); - cursym->autom = curauto; - curauto = 0; - } - s = p->from.sym; - if(s == S) { - diag("TEXT must have a name\n%P", p); - errorexit(); - } - cursym = s; - if(s->type != 0 && s->type != SXREF && (p->reg & DUPOK)) { - skip = 1; - goto casedef; - } - if(ntext++ == 0 && s->type != 0 && s->type != SXREF) { - /* redefinition, so file has probably been seen before */ - if(debug['v']) - Bprint(&bso, "skipping: %s: redefinition: %s", pn, s->name); - return; - } - skip = 0; - if(s->type != 0 && s->type != SXREF) - diag("redefinition: %s\n%P", s->name, p); - if(etextp) - etextp->next = s; - else - textp = s; - if(fromgotype) { - if(s->gotype && s->gotype != fromgotype) - diag("%s: type mismatch for %s", pn, s->name); - s->gotype = fromgotype; - } - etextp = s; - p->align = 4; - autosize = (p->to.offset+3L) & ~3L; - p->to.offset = autosize; - autosize += 4; - s->type = STEXT; - s->hist = gethist(); - s->text = p; - s->value = pc; - s->args = p->to.offset2; - lastp = p; - p->pc = pc; - pc++; - break; - - case ASUB: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = AADD; - } - goto casedef; - - case AADD: - if(p->from.type == D_CONST) - if(p->from.name == D_NONE) - if(p->from.offset < 0) { - p->from.offset = -p->from.offset; - p->as = ASUB; - } - goto casedef; - - case AMOVWD: - case AMOVWF: - case AMOVDW: - case AMOVFW: - case AMOVFD: - case AMOVDF: - // case AMOVF: - // case AMOVD: - case ACMPF: - case ACMPD: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - goto casedef; - - case AMOVF: - if(skip) - goto casedef; - - if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && - (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { - /* size sb 9 max */ - sprint(literal, "$%ux", ieeedtof(&p->from.ieee)); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, ieeedtof(&p->from.ieee)); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - case AMOVD: - if(skip) - goto casedef; - - if(p->from.type == D_FCONST && chipfloat(&p->from.ieee) < 0 && - (chipzero(&p->from.ieee) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) { - /* size sb 18 max */ - sprint(literal, "$%ux.%ux", - p->from.ieee.l, p->from.ieee.h); - s = lookup(literal, 0); - if(s->type == 0) { - s->type = SRODATA; - adduint32(s, p->from.ieee.l); - adduint32(s, p->from.ieee.h); - s->reachable = 0; - } - p->from.type = D_OREG; - p->from.sym = s; - p->from.name = D_EXTERN; - p->from.offset = 0; - } - goto casedef; - - default: - casedef: - if(skip) - nopout(p); - p->pc = pc; - pc++; - if(p->to.type == D_BRANCH) - p->to.offset += ipc; - if(lastp == nil) { - if(p->as != ANOP) - diag("unexpected instruction: %P", p); - break; - } - lastp->link = p; - lastp = p; - break; - } - goto loop; - -eof: - diag("truncated object file: %s", pn); -} - -Prog* -prg(void) -{ - Prog *p; - - p = mal(sizeof(Prog)); - *p = zprg; - return p; -} - -Prog* -appendp(Prog *q) -{ - Prog *p; - - p = prg(); - p->link = q->link; - q->link = p; - p->line = q->line; - return p; + s = linklookup(ctxt, "runtime.goarm", 0); + s->type = SRODATA; + adduint8(ctxt, s, ctxt->goarm); } diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c deleted file mode 100644 index 3d05d6d09..000000000 --- a/src/cmd/5l/optab.c +++ /dev/null @@ -1,277 +0,0 @@ -// Inferno utils/5l/optab.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/optab.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "l.h" - -Optab optab[] = -{ - /* struct Optab: - OPCODE, from, prog->reg, to, type,size,param,flag */ - { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 }, - { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 }, - - { AADD, C_REG, C_REG, C_REG, 1, 4, 0 }, - { AADD, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMVN, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { ACMP, C_REG, C_REG, C_NONE, 1, 4, 0 }, - - { AADD, C_RCON, C_REG, C_REG, 2, 4, 0 }, - { AADD, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0 }, - { ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0 }, - - { AADD, C_SHIFT,C_REG, C_REG, 3, 4, 0 }, - { AADD, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { AMVN, C_SHIFT,C_NONE, C_REG, 3, 4, 0 }, - { ACMP, C_SHIFT,C_REG, C_NONE, 3, 4, 0 }, - - { AMOVW, C_RACON,C_NONE, C_REG, 4, 4, REGSP }, - - { AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - { ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 }, - { ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 }, - - { AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL }, - { ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 }, - { ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0 }, - { ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0 }, - { ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0 }, - - { ASLL, C_RCON, C_REG, C_REG, 8, 4, 0 }, - { ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0 }, - - { ASLL, C_REG, C_NONE, C_REG, 9, 4, 0 }, - { ASLL, C_REG, C_REG, C_REG, 9, 4, 0 }, - - { ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0 }, - { ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 }, - - { AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0 }, - { AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 }, - - { AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 }, - { AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM }, - { AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4}, - - { AADD, C_NCON, C_REG, C_REG, 13, 8, 0 }, - { AADD, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0 }, - { ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0 }, - { AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM }, - { AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM }, - { ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM }, - - { AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0 }, - { AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0 }, - { AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0 }, - { AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0 }, - - { AMUL, C_REG, C_REG, C_REG, 15, 4, 0 }, - { AMUL, C_REG, C_NONE, C_REG, 15, 4, 0 }, - - { ADIV, C_REG, C_REG, C_REG, 16, 4, 0 }, - { ADIV, C_REG, C_NONE, C_REG, 16, 4, 0 }, - - { AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0 }, - { AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP }, - { AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0 }, - - { AMOVW, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVW, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - { AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP }, - { AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - { AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO }, - { AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO }, - { AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4 }, - - { AMOVW, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, - { AMOVW, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, - { AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, - { AMOVBU, C_LAUTO,C_NONE, C_REG, 31, 8, REGSP, LFROM }, - { AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM }, - { AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4 }, - - { AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM }, - - { AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 }, - { AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0 }, - { AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0 }, - - { AMOVM, C_LCON, C_NONE, C_SOREG, 38, 4, 0 }, - { AMOVM, C_SOREG,C_NONE, C_LCON, 39, 4, 0 }, - - { ASWPW, C_SOREG,C_REG, C_REG, 40, 4, 0 }, - - { ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0 }, - - { AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP }, - { AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0 }, - - { AMOVF, C_FAUTO,C_NONE, C_FREG, 51, 4, REGSP }, - { AMOVF, C_FOREG,C_NONE, C_FREG, 51, 4, 0 }, - - { AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO }, - { AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO }, - - { AMOVF, C_LAUTO,C_NONE, C_FREG, 53, 12, REGSP, LFROM }, - { AMOVF, C_LOREG,C_NONE, C_FREG, 53, 12, 0, LFROM }, - - { AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4 }, - { AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4}, - - { AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - { AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0 }, - { AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0 }, - { AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0 }, - - { AMOVW, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - { AMOVBU, C_SHIFT,C_NONE, C_REG, 59, 4, 0 }, - - { AMOVB, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - { AMOVBS, C_SHIFT,C_NONE, C_REG, 60, 4, 0 }, - - { AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - { AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0 }, - - { ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8 }, - { ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0 }, - - { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 }, - { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 }, - - { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVBS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVBS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHS, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHS, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 }, - { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 }, - - { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO }, - { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO }, - { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4 }, - - { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVBS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVBS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHS, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHS, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM }, - { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM }, - { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4 }, - - { ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 }, - { ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 }, - - { AMOVF, C_ZFCON,C_NONE, C_FREG, 80, 8, 0 }, - { AMOVF, C_SFCON,C_NONE, C_FREG, 81, 4, 0 }, - - { ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0 }, - { ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0 }, - - { AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0 }, - { AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0 }, - - { AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0 }, - { AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0 }, - - { AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0 }, - { AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0 }, - - { ATST, C_REG, C_NONE, C_NONE, 90, 4, 0 }, - - { ALDREXD, C_SOREG,C_NONE, C_REG, 91, 4, 0 }, - { ASTREXD, C_SOREG,C_REG, C_REG, 92, 4, 0 }, - - { APLD, C_SOREG,C_NONE, C_NONE, 95, 4, 0 }, - - { AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0 }, - - { ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0 }, - - { AMULWT, C_REG, C_REG, C_REG, 98, 4, 0 }, - { AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0 }, - - { AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0 }, - { APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0 }, - { AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0 }, - - { AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0 }, -}; diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c deleted file mode 100644 index cd8897989..000000000 --- a/src/cmd/5l/pass.c +++ /dev/null @@ -1,409 +0,0 @@ -// Inferno utils/5l/pass.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/pass.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Code and data passes. - -#include "l.h" -#include "../ld/lib.h" - -static void xfol(Prog*, Prog**); - -Prog* -brchain(Prog *p) -{ - int i; - - for(i=0; i<20; i++) { - if(p == P || p->as != AB) - return p; - p = p->cond; - } - return P; -} - -int -relinv(int a) -{ - switch(a) { - case ABEQ: return ABNE; - case ABNE: return ABEQ; - case ABCS: return ABCC; - case ABHS: return ABLO; - case ABCC: return ABCS; - case ABLO: return ABHS; - case ABMI: return ABPL; - case ABPL: return ABMI; - case ABVS: return ABVC; - case ABVC: return ABVS; - case ABHI: return ABLS; - case ABLS: return ABHI; - case ABGE: return ABLT; - case ABLT: return ABGE; - case ABGT: return ABLE; - case ABLE: return ABGT; - } - diag("unknown relation: %s", anames[a]); - return a; -} - -void -follow(void) -{ - Prog *firstp, *lastp; - - if(debug['v']) - Bprint(&bso, "%5.2f follow\n", cputime()); - Bflush(&bso); - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - firstp = prg(); - lastp = firstp; - xfol(cursym->text, &lastp); - lastp->link = nil; - cursym->text = firstp->link; - } -} - -static void -xfol(Prog *p, Prog **last) -{ - Prog *q, *r; - int a, i; - -loop: - if(p == P) - return; - a = p->as; - if(a == AB) { - q = p->cond; - if(q != P && q->as != ATEXT) { - p->mark |= FOLL; - p = q; - if(!(p->mark & FOLL)) - goto loop; - } - } - if(p->mark & FOLL) { - for(i=0,q=p; i<4; i++,q=q->link) { - if(q == *last || q == nil) - break; - a = q->as; - if(a == ANOP) { - i--; - continue; - } - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - goto copy; - if(q->cond == P || (q->cond->mark&FOLL)) - continue; - if(a != ABEQ && a != ABNE) - continue; - copy: - for(;;) { - r = prg(); - *r = *p; - if(!(r->mark&FOLL)) - print("can't happen 1\n"); - r->mark |= FOLL; - if(p != q) { - p = p->link; - (*last)->link = r; - *last = r; - continue; - } - (*last)->link = r; - *last = r; - if(a == AB || (a == ARET && q->scond == 14) || a == ARFE || a == AUNDEF) - return; - r->as = ABNE; - if(a == ABNE) - r->as = ABEQ; - r->cond = p->link; - r->link = p->cond; - if(!(r->link->mark&FOLL)) - xfol(r->link, last); - if(!(r->cond->mark&FOLL)) - print("can't happen 2\n"); - return; - } - } - a = AB; - q = prg(); - q->as = a; - q->line = p->line; - q->to.type = D_BRANCH; - q->to.offset = p->pc; - q->cond = p; - p = q; - } - p->mark |= FOLL; - (*last)->link = p; - *last = p; - if(a == AB || (a == ARET && p->scond == 14) || a == ARFE || a == AUNDEF){ - return; - } - if(p->cond != P) - if(a != ABL && a != ABX && p->link != P) { - q = brchain(p->link); - if(a != ATEXT && a != ABCASE) - if(q != P && (q->mark&FOLL)) { - p->as = relinv(a); - p->link = p->cond; - p->cond = q; - } - xfol(p->link, last); - q = brchain(p->cond); - if(q == P) - q = p->cond; - if(q->mark&FOLL) { - p->cond = q; - return; - } - p = q; - goto loop; - } - p = p->link; - goto loop; -} - -void -patch(void) -{ - int32 c, vexit; - Prog *p, *q; - Sym *s; - int a; - - if(debug['v']) - Bprint(&bso, "%5.2f patch\n", cputime()); - Bflush(&bso); - mkfwd(); - s = lookup("exit", 0); - vexit = s->value; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - a = p->as; - if((a == ABL || a == ABX || a == AB || a == ARET) && - p->to.type != D_BRANCH && p->to.sym != S) { - s = p->to.sym; - if(s->text == nil) - continue; - switch(s->type&SMASK) { - default: - diag("undefined: %s", s->name); - s->type = STEXT; - s->value = vexit; - continue; // avoid more error messages - case STEXT: - p->to.offset = s->value; - p->to.type = D_BRANCH; - p->cond = s->text; - continue; - } - } - if(p->to.type != D_BRANCH) - continue; - c = p->to.offset; - for(q = cursym->text; q != P;) { - if(c == q->pc) - break; - if(q->forwd != P && c >= q->forwd->pc) - q = q->forwd; - else - q = q->link; - } - if(q == P) { - diag("branch out of range %d\n%P", c, p); - p->to.type = D_NONE; - } - p->cond = q; - } - } - if(flag_shared) { - s = lookup("init_array", 0); - s->type = SINITARR; - s->reachable = 1; - s->hide = 1; - addaddr(s, lookup(INITENTRY, 0)); - } - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - for(p = cursym->text; p != P; p = p->link) { - if(p->cond != P) { - p->cond = brloop(p->cond); - if(p->cond != P) - if(p->to.type == D_BRANCH) - p->to.offset = p->cond->pc; - } - } - } -} - -Prog* -brloop(Prog *p) -{ - Prog *q; - int c; - - for(c=0; p!=P;) { - if(p->as != AB) - return p; - q = p->cond; - if(q <= p) { - c++; - if(q == p || c > 5000) - break; - } - p = q; - } - return P; -} - -int32 -atolwhex(char *s) -{ - int32 n; - int f; - - n = 0; - f = 0; - while(*s == ' ' || *s == '\t') - s++; - if(*s == '-' || *s == '+') { - if(*s++ == '-') - f = 1; - while(*s == ' ' || *s == '\t') - s++; - } - if(s[0]=='0' && s[1]){ - if(s[1]=='x' || s[1]=='X'){ - s += 2; - for(;;){ - if(*s >= '0' && *s <= '9') - n = n*16 + *s++ - '0'; - else if(*s >= 'a' && *s <= 'f') - n = n*16 + *s++ - 'a' + 10; - else if(*s >= 'A' && *s <= 'F') - n = n*16 + *s++ - 'A' + 10; - else - break; - } - } else - while(*s >= '0' && *s <= '7') - n = n*8 + *s++ - '0'; - } else - while(*s >= '0' && *s <= '9') - n = n*10 + *s++ - '0'; - if(f) - n = -n; - return n; -} - -int32 -rnd(int32 v, int32 r) -{ - int32 c; - - if(r <= 0) - return v; - v += r - 1; - c = v % r; - if(c < 0) - c += r; - v -= c; - return v; -} - -void -dozerostk(void) -{ - Prog *p, *pl; - int32 autoffset; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(cursym->text == nil || cursym->text->link == nil) - continue; - p = cursym->text; - autoffset = p->to.offset; - if(autoffset < 0) - autoffset = 0; - if(autoffset && !(p->reg&NOSPLIT)) { - // MOVW $4(R13), R1 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4; - p->to.type = D_REG; - p->to.reg = 1; - - // MOVW $n(R13), R2 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.reg = 13; - p->from.offset = 4 + autoffset; - p->to.type = D_REG; - p->to.reg = 2; - - // MOVW $0, R3 - p = appendp(p); - p->as = AMOVW; - p->from.type = D_CONST; - p->from.offset = 0; - p->to.type = D_REG; - p->to.reg = 3; - - // L: - // MOVW.P R3, 0(R1) +4 - // CMP R1, R2 - // BNE L - p = pl = appendp(p); - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = 3; - p->to.type = D_OREG; - p->to.reg = 1; - p->to.offset = 4; - p->scond |= C_PBIT; - - p = appendp(p); - p->as = ACMP; - p->from.type = D_REG; - p->from.reg = 1; - p->reg = 2; - - p = appendp(p); - p->as = ABNE; - p->to.type = D_BRANCH; - p->cond = pl; - } - } -} diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c deleted file mode 100644 index 225a52435..000000000 --- a/src/cmd/5l/prof.c +++ /dev/null @@ -1,211 +0,0 @@ -// Inferno utils/5l/obj.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Profiling. - -#include "l.h" -#include "../ld/lib.h" - -void -doprof1(void) -{ -#ifdef NOTDEF // TODO(rsc) - Sym *s; - int32 n; - Prog *p, *q; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 1\n", cputime()); - Bflush(&bso); - s = lookup("__mcount", 0); - n = 1; - for(p = firstp->link; p != P; p = p->link) { - if(p->as == ATEXT) { - q = prg(); - q->line = p->line; - q->link = datap; - datap = q; - q->as = ADATA; - q->from.type = D_OREG; - q->from.name = D_EXTERN; - q->from.offset = n*4; - q->from.sym = s; - q->reg = 4; - q->to = p->from; - q->to.type = D_CONST; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AMOVW; - p->from.type = D_OREG; - p->from.name = D_EXTERN; - p->from.sym = s; - p->from.offset = n*4 + 4; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AADD; - p->from.type = D_CONST; - p->from.offset = 1; - p->to.type = D_REG; - p->to.reg = REGTMP; - - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = AMOVW; - p->from.type = D_REG; - p->from.reg = REGTMP; - p->to.type = D_OREG; - p->to.name = D_EXTERN; - p->to.sym = s; - p->to.offset = n*4 + 4; - - n += 2; - continue; - } - } - q = prg(); - q->line = 0; - q->link = datap; - datap = q; - - q->as = ADATA; - q->from.type = D_OREG; - q->from.name = D_EXTERN; - q->from.sym = s; - q->reg = 4; - q->to.type = D_CONST; - q->to.offset = n; - - s->type = SBSS; - s->value = n*4; -#endif -} - -void -doprof2(void) -{ - Sym *s2, *s4; - Prog *p, *q, *ps2, *ps4; - - if(debug['v']) - Bprint(&bso, "%5.2f profile 2\n", cputime()); - Bflush(&bso); - s2 = lookup("_profin", 0); - s4 = lookup("_profout", 0); - if(s2->type != STEXT || s4->type != STEXT) { - diag("_profin/_profout not defined"); - return; - } - ps2 = P; - ps4 = P; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(cursym == s2) { - ps2 = p; - p->reg = 1; - } - if(cursym == s4) { - ps4 = p; - p->reg = 1; - } - } - for(cursym = textp; cursym != nil; cursym = cursym->next) - for(p = cursym->text; p != P; p = p->link) { - if(p->as == ATEXT) { - if(p->reg & NOPROF) { - for(;;) { - q = p->link; - if(q == P) - break; - if(q->as == ATEXT) - break; - p = q; - } - continue; - } - - /* - * BL profin, R2 - */ - q = prg(); - q->line = p->line; - q->pc = p->pc; - q->link = p->link; - p->link = q; - p = q; - p->as = ABL; - p->to.type = D_BRANCH; - p->cond = ps2; - p->to.sym = s2; - - continue; - } - if(p->as == ARET) { - /* - * RET - */ - q = prg(); - q->as = ARET; - q->from = p->from; - q->to = p->to; - q->link = p->link; - p->link = q; - - /* - * BL profout - */ - p->as = ABL; - p->from = zprg.from; - p->to = zprg.to; - p->to.type = D_BRANCH; - p->cond = ps4; - p->to.sym = s4; - - p = q; - - continue; - } - } -} diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c deleted file mode 100644 index de6481c71..000000000 --- a/src/cmd/5l/softfloat.c +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "l.h" -#include "../ld/lib.h" - -// Software floating point. - -void -softfloat(void) -{ - Prog *p, *next, *psfloat; - Sym *symsfloat; - int wasfloat; - - if(!debug['F']) - return; - - symsfloat = lookup("_sfloat", 0); - psfloat = P; - if(symsfloat->type == STEXT) - psfloat = symsfloat->text; - - for(cursym = textp; cursym != nil; cursym = cursym->next) { - wasfloat = 0; - for(p = cursym->text; p != P; p = p->link) - if(p->cond != P) - p->cond->mark |= LABEL; - for(p = cursym->text; p != P; p = p->link) { - switch(p->as) { - case AMOVW: - if(p->to.type == D_FREG || p->from.type == D_FREG) - goto soft; - goto notsoft; - - case AMOVWD: - case AMOVWF: - case AMOVDW: - case AMOVFW: - case AMOVFD: - case AMOVDF: - case AMOVF: - case AMOVD: - - case ACMPF: - case ACMPD: - case AADDF: - case AADDD: - case ASUBF: - case ASUBD: - case AMULF: - case AMULD: - case ADIVF: - case ADIVD: - case ASQRTF: - case ASQRTD: - case AABSF: - case AABSD: - goto soft; - - default: - goto notsoft; - - soft: - if (psfloat == P) - diag("floats used with _sfloat not defined"); - if (!wasfloat || (p->mark&LABEL)) { - next = prg(); - *next = *p; - - // BL _sfloat(SB) - *p = zprg; - p->link = next; - p->as = ABL; - p->to.type = D_BRANCH; - p->to.sym = symsfloat; - p->cond = psfloat; - p->line = next->line; - - p = next; - wasfloat = 1; - } - break; - - notsoft: - wasfloat = 0; - } - } - } -} diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c deleted file mode 100644 index e7cc0b4b1..000000000 --- a/src/cmd/5l/span.c +++ /dev/null @@ -1,937 +0,0 @@ -// Inferno utils/5l/span.c -// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c -// -// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) -// Portions Copyright © 1997-1999 Vita Nuova Limited -// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) -// Portions Copyright © 2004,2006 Bruce Ellis -// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) -// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others -// Portions Copyright © 2009 The Go Authors. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Instruction layout. - -#include "l.h" -#include "../ld/lib.h" - -static struct { - uint32 start; - uint32 size; - uint32 extra; -} pool; - -int checkpool(Prog*, int); -int flushpool(Prog*, int, int); - -int -isbranch(Prog *p) -{ - int as = p->as; - return (as >= ABEQ && as <= ABLE) || as == AB || as == ABL || as == ABX; -} - -static int -scan(Prog *op, Prog *p, int c) -{ - Prog *q; - - for(q = op->link; q != p && q != P; q = q->link){ - q->pc = c; - c += oplook(q)->size; - nocache(q); - } - return c; -} - -/* size of a case statement including jump table */ -static int32 -casesz(Prog *p) -{ - int jt = 0; - int32 n = 0; - Optab *o; - - for( ; p != P; p = p->link){ - if(p->as == ABCASE) - jt = 1; - else if(jt) - break; - o = oplook(p); - n += o->size; - } - return n; -} - -void -span(void) -{ - Prog *p, *op; - Optab *o; - int m, bflag, i, v; - int32 c, otxt, out[6]; - Section *sect; - uchar *bp; - Sym *sub, *gmsym; - - if(debug['v']) - Bprint(&bso, "%5.2f span\n", cputime()); - Bflush(&bso); - - sect = addsection(&segtext, ".text", 05); - lookup("text", 0)->sect = sect; - lookup("etext", 0)->sect = sect; - - bflag = 0; - c = INITTEXT; - otxt = c; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - cursym->sect = sect; - p = cursym->text; - if(p == P || p->link == P) { // handle external functions and ELF section symbols - if(cursym->type & SSUB) - continue; - if(cursym->align != 0) - c = rnd(c, cursym->align); - cursym->value = 0; - for(sub = cursym; sub != S; sub = sub->sub) { - sub->value += c; - for(p = sub->text; p != P; p = p->link) - p->pc += sub->value; - } - c += cursym->size; - continue; - } - p->pc = c; - cursym->value = c; - - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; - /* need passes to resolve branches */ - if(c-otxt >= 1L<<17) - bflag = 1; - otxt = c; - - for(op = p, p = p->link; p != P; op = p, p = p->link) { - curp = p; - p->pc = c; - o = oplook(p); - m = o->size; - // must check literal pool here in case p generates many instructions - if(blitrl){ - if(checkpool(op, p->as == ACASE ? casesz(p) : m)) - c = p->pc = scan(op, p, c); - } - if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { - diag("zero-width instruction\n%P", p); - continue; - } - switch(o->flag & (LFROM|LTO|LPOOL)) { - case LFROM: - addpool(p, &p->from); - break; - case LTO: - addpool(p, &p->to); - break; - case LPOOL: - if ((p->scond&C_SCOND) == 14) - flushpool(p, 0, 0); - break; - } - if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == 14) - flushpool(p, 0, 0); - c += m; - } - if(blitrl){ - if(checkpool(op, 0)) - c = scan(op, P, c); - } - cursym->size = c - cursym->value; - } - - /* - * if any procedure is large enough to - * generate a large SBRA branch, then - * generate extra passes putting branches - * around jmps to fix. this is rare. - */ - while(bflag) { - if(debug['v']) - Bprint(&bso, "%5.2f span1\n", cputime()); - bflag = 0; - c = INITTEXT; - for(cursym = textp; cursym != nil; cursym = cursym->next) { - if(!cursym->text || !cursym->text->link) - continue; - cursym->value = c; - for(p = cursym->text; p != P; p = p->link) { - curp = p; - p->pc = c; - o = oplook(p); -/* very large branches - if(o->type == 6 && p->cond) { - otxt = p->cond->pc - c; - if(otxt < 0) - otxt = -otxt; - if(otxt >= (1L<<17) - 10) { - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = p->cond; - p->cond = q; - q = prg(); - q->link = p->link; - p->link = q; - q->as = AB; - q->to.type = D_BRANCH; - q->cond = q->link->link; - bflag = 1; - } - } - */ - m = o->size; - if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA)) { - if(p->as == ATEXT) { - autosize = p->to.offset + 4; - if(p->from.sym != S) - p->from.sym->value = c; - continue; - } - diag("zero-width instruction\n%P", p); - continue; - } - c += m; - } - cursym->size = c - cursym->value; - } - } - - c = rnd(c, 8); - - /* - * lay out the code. all the pc-relative code references, - * even cross-function, are resolved now; - * only data references need to be relocated. - * with more work we could leave cross-function - * code references to be relocated too, and then - * perhaps we'd be able to parallelize the span loop above. - */ - gmsym = S; - if(linkmode == LinkExternal) - gmsym = lookup("runtime.tlsgm", 0); - for(cursym = textp; cursym != nil; cursym = cursym->next) { - p = cursym->text; - if(p == P || p->link == P) - continue; - autosize = p->to.offset + 4; - symgrow(cursym, cursym->size); - - bp = cursym->p; - for(p = p->link; p != P; p = p->link) { - pc = p->pc; - curp = p; - o = oplook(p); - asmout(p, o, out, gmsym); - for(i=0; i<o->size/4; i++) { - v = out[i]; - *bp++ = v; - *bp++ = v>>8; - *bp++ = v>>16; - *bp++ = v>>24; - } - } - } - sect->vaddr = INITTEXT; - sect->len = c - INITTEXT; -} - -/* - * when the first reference to the literal pool threatens - * to go out of range of a 12-bit PC-relative offset, - * drop the pool now, and branch round it. - * this happens only in extended basic blocks that exceed 4k. - */ -int -checkpool(Prog *p, int sz) -{ - if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0) - return flushpool(p, 1, 0); - else if(p->link == P) - return flushpool(p, 2, 0); - return 0; -} - -int -flushpool(Prog *p, int skip, int force) -{ - Prog *q; - - if(blitrl) { - if(skip){ - if(0 && skip==1)print("note: flush literal pool at %ux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start); - q = prg(); - q->as = AB; - q->to.type = D_BRANCH; - q->cond = p->link; - q->link = blitrl; - q->line = p->line; - blitrl = q; - } - else if(!force && (p->pc+pool.size-pool.start < 2048)) - return 0; - elitrl->link = p->link; - p->link = blitrl; - // BUG(minux): how to correctly handle line number for constant pool entries? - // for now, we set line number to the last instruction preceding them at least - // this won't bloat the .debug_line tables - while(blitrl) { - blitrl->line = p->line; - blitrl = blitrl->link; - } - blitrl = 0; /* BUG: should refer back to values until out-of-range */ - elitrl = 0; - pool.size = 0; - pool.start = 0; - pool.extra = 0; - return 1; - } - return 0; -} - -void -addpool(Prog *p, Adr *a) -{ - Prog *q, t; - int c; - - c = aclass(a); - - t = zprg; - t.as = AWORD; - - switch(c) { - default: - t.to = *a; - if(flag_shared && t.to.sym != S) - t.pcrel = p; - break; - - case C_SROREG: - case C_LOREG: - case C_ROREG: - case C_FOREG: - case C_SOREG: - case C_HOREG: - case C_FAUTO: - case C_SAUTO: - case C_LAUTO: - case C_LACON: - t.to.type = D_CONST; - t.to.offset = instoffset; - break; - } - - if(t.pcrel == P) { - for(q = blitrl; q != P; q = q->link) /* could hash on t.t0.offset */ - if(q->pcrel == P && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) { - p->cond = q; - return; - } - } - - q = prg(); - *q = t; - q->pc = pool.size; - - if(blitrl == P) { - blitrl = q; - pool.start = p->pc; - q->align = 4; - } else - elitrl->link = q; - elitrl = q; - pool.size += 4; - - p->cond = q; -} - -void -xdefine(char *p, int t, int32 v) -{ - Sym *s; - - s = lookup(p, 0); - s->type = t; - s->value = v; - s->reachable = 1; - s->special = 1; -} - -int32 -regoff(Adr *a) -{ - - instoffset = 0; - aclass(a); - return instoffset; -} - -int32 -immrot(uint32 v) -{ - int i; - - for(i=0; i<16; i++) { - if((v & ~0xff) == 0) - return (i<<8) | v | (1<<25); - v = (v<<2) | (v>>30); - } - return 0; -} - -int32 -immaddr(int32 v) -{ - if(v >= 0 && v <= 0xfff) - return (v & 0xfff) | - (1<<24) | /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xfff && v < 0) - return (-v & 0xfff) | - (1<<24); /* pre indexing */ - return 0; -} - -int -immfloat(int32 v) -{ - return (v & 0xC03) == 0; /* offset will fit in floating-point load/store */ -} - -int -immhalf(int32 v) -{ - if(v >= 0 && v <= 0xff) - return v| - (1<<24)| /* pre indexing */ - (1<<23); /* pre indexing, up */ - if(v >= -0xff && v < 0) - return (-v & 0xff)| - (1<<24); /* pre indexing */ - return 0; -} - -int32 -symaddr(Sym *s) -{ - if(!s->reachable) - diag("unreachable symbol in symaddr - %s", s->name); - return s->value; -} - -int -aclass(Adr *a) -{ - Sym *s; - int t; - - switch(a->type) { - case D_NONE: - return C_NONE; - - case D_REG: - return C_REG; - - case D_REGREG: - return C_REGREG; - - case D_REGREG2: - return C_REGREG2; - - case D_SHIFT: - return C_SHIFT; - - case D_FREG: - return C_FREG; - - case D_FPCR: - return C_FCR; - - case D_OREG: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - if(a->sym == 0 || a->sym->name == 0) { - print("null sym external\n"); - print("%D\n", a); - return C_GOK; - } - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - t = immaddr(instoffset); - if(t){ - if(immhalf(instoffset)) - return immfloat(t) ? C_HFAUTO : C_HAUTO; - if(immfloat(t)) - return C_FAUTO; - return C_SAUTO; - } - return C_LAUTO; - case D_NONE: - instoffset = a->offset; - t = immaddr(instoffset); - if(t) { - if(immhalf(instoffset)) /* n.b. that it will also satisfy immrot */ - return immfloat(t) ? C_HFOREG : C_HOREG; - if(immfloat(t)) - return C_FOREG; /* n.b. that it will also satisfy immrot */ - t = immrot(instoffset); - if(t) - return C_SROREG; - if(immhalf(instoffset)) - return C_HOREG; - return C_SOREG; - } - t = immrot(instoffset); - if(t) - return C_ROREG; - return C_LOREG; - } - return C_GOK; - - case D_PSR: - return C_PSR; - - case D_OCONST: - switch(a->name) { - case D_EXTERN: - case D_STATIC: - instoffset = 0; // s.b. unused but just in case - return C_ADDR; - } - return C_GOK; - - case D_FCONST: - if(chipzero(&a->ieee) >= 0) - return C_ZFCON; - if(chipfloat(&a->ieee) >= 0) - return C_SFCON; - return C_LFCON; - - case D_CONST: - case D_CONST2: - switch(a->name) { - - case D_NONE: - instoffset = a->offset; - if(a->reg != NREG) - goto aconsize; - - t = immrot(instoffset); - if(t) - return C_RCON; - t = immrot(~instoffset); - if(t) - return C_NCON; - return C_LCON; - - case D_EXTERN: - case D_STATIC: - s = a->sym; - if(s == S) - break; - instoffset = 0; // s.b. unused but just in case - return C_LCONADDR; - - case D_AUTO: - instoffset = autosize + a->offset; - goto aconsize; - - case D_PARAM: - instoffset = autosize + a->offset + 4L; - aconsize: - t = immrot(instoffset); - if(t) - return C_RACON; - return C_LACON; - } - return C_GOK; - - case D_BRANCH: - return C_SBRA; - } - return C_GOK; -} - -Optab* -oplook(Prog *p) -{ - int a1, a2, a3, r; - char *c1, *c3; - Optab *o, *e; - - a1 = p->optab; - if(a1) - return optab+(a1-1); - a1 = p->from.class; - if(a1 == 0) { - a1 = aclass(&p->from) + 1; - p->from.class = a1; - } - a1--; - a3 = p->to.class; - if(a3 == 0) { - a3 = aclass(&p->to) + 1; - p->to.class = a3; - } - a3--; - a2 = C_NONE; - if(p->reg != NREG) - a2 = C_REG; - r = p->as; - o = oprange[r].start; - if(o == 0) { - a1 = opcross[repop[r]][a1][a2][a3]; - if(a1) { - p->optab = a1+1; - return optab+a1; - } - o = oprange[r].stop; /* just generate an error */ - } - if(debug['O']) { - print("oplook %A %O %O %O\n", - (int)p->as, a1, a2, a3); - print(" %d %d\n", p->from.type, p->to.type); - } - e = oprange[r].stop; - c1 = xcmp[a1]; - c3 = xcmp[a3]; - for(; o<e; o++) - if(o->a2 == a2) - if(c1[o->a1]) - if(c3[o->a3]) { - p->optab = (o-optab)+1; - return o; - } - diag("illegal combination %A %O %O %O, %d %d", - p->as, a1, a2, a3, p->from.type, p->to.type); - prasm(p); - if(o == 0) - o = optab; - return o; -} - -int -cmp(int a, int b) -{ - - if(a == b) - return 1; - switch(a) { - case C_LCON: - if(b == C_RCON || b == C_NCON) - return 1; - break; - case C_LACON: - if(b == C_RACON) - return 1; - break; - case C_LFCON: - if(b == C_ZFCON || b == C_SFCON) - return 1; - break; - - case C_HFAUTO: - return b == C_HAUTO || b == C_FAUTO; - case C_FAUTO: - case C_HAUTO: - return b == C_HFAUTO; - case C_SAUTO: - return cmp(C_HFAUTO, b); - case C_LAUTO: - return cmp(C_SAUTO, b); - - case C_HFOREG: - return b == C_HOREG || b == C_FOREG; - case C_FOREG: - case C_HOREG: - return b == C_HFOREG; - case C_SROREG: - return cmp(C_SOREG, b) || cmp(C_ROREG, b); - case C_SOREG: - case C_ROREG: - return b == C_SROREG || cmp(C_HFOREG, b); - case C_LOREG: - return cmp(C_SROREG, b); - - case C_LBRA: - if(b == C_SBRA) - return 1; - break; - - case C_HREG: - return cmp(C_SP, b) || cmp(C_PC, b); - - } - return 0; -} - -int -ocmp(const void *a1, const void *a2) -{ - Optab *p1, *p2; - int n; - - p1 = (Optab*)a1; - p2 = (Optab*)a2; - n = p1->as - p2->as; - if(n) - return n; - n = p1->a1 - p2->a1; - if(n) - return n; - n = p1->a2 - p2->a2; - if(n) - return n; - n = p1->a3 - p2->a3; - if(n) - return n; - return 0; -} - -void -buildop(void) -{ - int i, n, r; - - for(i=0; i<C_GOK; i++) - for(n=0; n<C_GOK; n++) - xcmp[i][n] = cmp(n, i); - for(n=0; optab[n].as != AXXX; n++) { - if((optab[n].flag & LPCREL) != 0) { - if(flag_shared) - optab[n].size += optab[n].pcrelsiz; - else - optab[n].flag &= ~LPCREL; - } - } - qsort(optab, n, sizeof(optab[0]), ocmp); - for(i=0; i<n; i++) { - r = optab[i].as; - oprange[r].start = optab+i; - while(optab[i].as == r) - i++; - oprange[r].stop = optab+i; - i--; - - switch(r) - { - default: - diag("unknown op in build: %A", r); - errorexit(); - case AADD: - oprange[AAND] = oprange[r]; - oprange[AEOR] = oprange[r]; - oprange[ASUB] = oprange[r]; - oprange[ARSB] = oprange[r]; - oprange[AADC] = oprange[r]; - oprange[ASBC] = oprange[r]; - oprange[ARSC] = oprange[r]; - oprange[AORR] = oprange[r]; - oprange[ABIC] = oprange[r]; - break; - case ACMP: - oprange[ATEQ] = oprange[r]; - oprange[ACMN] = oprange[r]; - break; - case AMVN: - break; - case ABEQ: - oprange[ABNE] = oprange[r]; - oprange[ABCS] = oprange[r]; - oprange[ABHS] = oprange[r]; - oprange[ABCC] = oprange[r]; - oprange[ABLO] = oprange[r]; - oprange[ABMI] = oprange[r]; - oprange[ABPL] = oprange[r]; - oprange[ABVS] = oprange[r]; - oprange[ABVC] = oprange[r]; - oprange[ABHI] = oprange[r]; - oprange[ABLS] = oprange[r]; - oprange[ABGE] = oprange[r]; - oprange[ABLT] = oprange[r]; - oprange[ABGT] = oprange[r]; - oprange[ABLE] = oprange[r]; - break; - case ASLL: - oprange[ASRL] = oprange[r]; - oprange[ASRA] = oprange[r]; - break; - case AMUL: - oprange[AMULU] = oprange[r]; - break; - case ADIV: - oprange[AMOD] = oprange[r]; - oprange[AMODU] = oprange[r]; - oprange[ADIVU] = oprange[r]; - break; - case AMOVW: - case AMOVB: - case AMOVBS: - case AMOVBU: - case AMOVH: - case AMOVHS: - case AMOVHU: - break; - case ASWPW: - oprange[ASWPBU] = oprange[r]; - break; - case AB: - case ABL: - case ABX: - case ABXRET: - case ASWI: - case AWORD: - case AMOVM: - case ARFE: - case ATEXT: - case AUSEFIELD: - case ACASE: - case ABCASE: - case ATYPE: - break; - case AADDF: - oprange[AADDD] = oprange[r]; - oprange[ASUBF] = oprange[r]; - oprange[ASUBD] = oprange[r]; - oprange[AMULF] = oprange[r]; - oprange[AMULD] = oprange[r]; - oprange[ADIVF] = oprange[r]; - oprange[ADIVD] = oprange[r]; - oprange[ASQRTF] = oprange[r]; - oprange[ASQRTD] = oprange[r]; - oprange[AMOVFD] = oprange[r]; - oprange[AMOVDF] = oprange[r]; - oprange[AABSF] = oprange[r]; - oprange[AABSD] = oprange[r]; - break; - - case ACMPF: - oprange[ACMPD] = oprange[r]; - break; - - case AMOVF: - oprange[AMOVD] = oprange[r]; - break; - - case AMOVFW: - oprange[AMOVDW] = oprange[r]; - break; - - case AMOVWF: - oprange[AMOVWD] = oprange[r]; - break; - - case AMULL: - oprange[AMULAL] = oprange[r]; - oprange[AMULLU] = oprange[r]; - oprange[AMULALU] = oprange[r]; - break; - - case AMULWT: - oprange[AMULWB] = oprange[r]; - break; - - case AMULAWT: - oprange[AMULAWB] = oprange[r]; - break; - - case AMULA: - case ALDREX: - case ASTREX: - case ALDREXD: - case ASTREXD: - case ATST: - case APLD: - case AUNDEF: - case ACLZ: - case AFUNCDATA: - case APCDATA: - break; - } - } -} - -/* -void -buildrep(int x, int as) -{ - Opcross *p; - Optab *e, *s, *o; - int a1, a2, a3, n; - - if(C_NONE != 0 || C_REG != 1 || C_GOK >= 32 || x >= nelem(opcross)) { - diag("assumptions fail in buildrep"); - errorexit(); - } - repop[as] = x; - p = (opcross + x); - s = oprange[as].start; - e = oprange[as].stop; - for(o=e-1; o>=s; o--) { - n = o-optab; - for(a2=0; a2<2; a2++) { - if(a2) { - if(o->a2 == C_NONE) - continue; - } else - if(o->a2 != C_NONE) - continue; - for(a1=0; a1<32; a1++) { - if(!xcmp[a1][o->a1]) - continue; - for(a3=0; a3<32; a3++) - if(xcmp[a3][o->a3]) - (*p)[a1][a2][a3] = n; - } - } - } - oprange[as].start = 0; -} -*/ |