From 505c19580e0f43fe5224431459cacb7c21edd93d Mon Sep 17 00:00:00 2001 From: Ondřej Surý Date: Fri, 6 Apr 2012 15:14:11 +0200 Subject: Imported Upstream version 1 --- src/cmd/8l/8.out.h | 14 +++++++-- src/cmd/8l/Makefile | 48 ++---------------------------- src/cmd/8l/asm.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--------- src/cmd/8l/doc.go | 43 ++------------------------- src/cmd/8l/l.h | 2 ++ src/cmd/8l/obj.c | 52 +++++++++++++++++++++----------- src/cmd/8l/optab.c | 14 +++++++-- src/cmd/8l/pass.c | 27 ++++++++++++----- src/cmd/8l/span.c | 39 ++++++++++++++++-------- 9 files changed, 182 insertions(+), 142 deletions(-) (limited to 'src/cmd/8l') diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h index 9a8483aaf..9d2751cf0 100644 --- a/src/cmd/8l/8.out.h +++ b/src/cmd/8l/8.out.h @@ -34,6 +34,7 @@ #define DUPOK (1<<1) #define NOSPLIT (1<<2) #define RODATA (1<<3) +#define NOPTR (1<<4) enum as { @@ -115,7 +116,8 @@ enum as AIRETW, AJCC, AJCS, - AJCXZ, + AJCXZL, + AJCXZW, AJEQ, AJGE, AJGT, @@ -394,7 +396,9 @@ enum as ACMPXCHGL, ACMPXCHGW, ACMPXCHG8B, - + + ARDTSC, + AXADDB, AXADDL, AXADDW, @@ -442,6 +446,12 @@ enum as AFCMOVNU, AFCMOVUN, + ALFENCE, + AMFENCE, + ASFENCE, + + AEMMS, + ALAST }; diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile index 7d34e1704..3f528d751 100644 --- a/src/cmd/8l/Makefile +++ b/src/cmd/8l/Makefile @@ -1,49 +1,5 @@ -# Copyright 2009 The Go Authors. All rights reserved. +# Copyright 2012 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 ../../Make.inc -O:=$(HOST_O) - -TARG=8l - -OFILES=\ - asm.$O\ - data.$O\ - dwarf.$O\ - elf.$O\ - enam.$O\ - go.$O\ - ldelf.$O\ - ldmacho.$O\ - ldpe.$O\ - lib.$O\ - list.$O\ - macho.$O\ - obj.$O\ - optab.$O\ - pass.$O\ - pe.$O\ - prof.$O\ - span.$O\ - symtab.$O\ - - -HFILES=\ - l.h\ - 8.out.h\ - ../ld/dwarf.h\ - ../ld/elf.h\ - ../ld/macho.h\ - ../ld/pe.h\ - -include ../../Make.ccmd - -enam.c: 8.out.h - sh mkenam - -CLEANFILES+=enam.c - - -%.$O: ../ld/%.c - $(HOST_CC) $(HOST_CFLAGS) -c -I. ../ld/$*.c +include ../../Make.dist diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 22abd8049..25ffc786f 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -37,10 +37,10 @@ #include "../ld/macho.h" #include "../ld/pe.h" -#define Dbufslop 100 - char linuxdynld[] = "/lib/ld-linux.so.2"; char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; +char openbsddynld[] = "/usr/libexec/ld.so"; +char netbsddynld[] = "/usr/libexec/ld.elf_so"; int32 entryvalue(void) @@ -90,6 +90,9 @@ enum { ElfStrPlt, ElfStrGnuVersion, ElfStrGnuVersionR, + ElfStrNoteNetbsdIdent, + ElfStrNoPtrData, + ElfStrNoPtrBss, NElfStr }; @@ -107,6 +110,7 @@ needlib(char *name) /* reuse hash code in symbol table */ p = smprint(".dynlib.%s", name); s = lookup(p, 0); + free(p); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. return 1; @@ -416,7 +420,7 @@ adddynsym(Sym *s) return; if(s->dynimpname == nil) - diag("adddynsym: no dynamic name for %s", s->name, *(int32*)0); + diag("adddynsym: no dynamic name for %s", s->name); if(iself) { s->dynid = nelfsym++; @@ -524,8 +528,12 @@ doelf(void) elfstr[ElfStrEmpty] = addstring(shstrtab, ""); elfstr[ElfStrText] = addstring(shstrtab, ".text"); + elfstr[ElfStrNoPtrData] = addstring(shstrtab, ".noptrdata"); elfstr[ElfStrData] = addstring(shstrtab, ".data"); elfstr[ElfStrBss] = addstring(shstrtab, ".bss"); + elfstr[ElfStrNoPtrBss] = addstring(shstrtab, ".noptrbss"); + if(HEADTYPE == Hnetbsd) + elfstr[ElfStrNoteNetbsdIdent] = addstring(shstrtab, ".note.netbsd.ident"); addstring(shstrtab, ".elfdata"); addstring(shstrtab, ".rodata"); addstring(shstrtab, ".gosymtab"); @@ -606,7 +614,7 @@ doelf(void) /* define dynamic elf table */ s = lookup(".dynamic", 0); s->reachable = 1; - s->type = SELFROSECT; + s->type = SELFSECT; // writable /* * .dynamic table @@ -626,6 +634,8 @@ doelf(void) elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0)); elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0)); + elfwritedynent(s, DT_DEBUG, 0); + // Do not write DT_NULL. elfdynhash will finish it. } } @@ -657,7 +667,7 @@ asmb(void) { int32 v, magic; int a, dynsym; - uint32 symo, startva, machlink; + uint32 symo, startva, dwarfoff, machlink, resoff; ElfEhdr *eh; ElfPhdr *ph, *pph; ElfShdr *sh; @@ -688,8 +698,19 @@ asmb(void) datblk(segdata.vaddr, segdata.filelen); machlink = 0; - if(HEADTYPE == Hdarwin) + if(HEADTYPE == Hdarwin) { + if(debug['v']) + Bprint(&bso, "%5.2f dwarf\n", cputime()); + + dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND); + cseek(dwarfoff); + + segdwarf.fileoff = cpos(); + dwarfemitdebugsections(); + segdwarf.filelen = cpos() - segdwarf.fileoff; + machlink = domacholink(); + } if(iself) { /* index of elf text section; needed by asmelfsym, double-checked below */ @@ -700,6 +721,8 @@ asmb(void) if(elfverneed) elftextsh += 2; } + if(HEADTYPE == Hnetbsd) + elftextsh += 1; } symsize = 0; @@ -746,7 +769,7 @@ asmb(void) default: if(iself) { if(debug['v']) - Bprint(&bso, "%5.2f elfsym\n", cputime()); + Bprint(&bso, "%5.2f elfsym\n", cputime()); asmelfsym(); cflush(); cwrite(elfstrdat, elfstrsize); @@ -769,7 +792,6 @@ asmb(void) cflush(); } break; - case Hdarwin: case Hwindows: if(debug['v']) Bprint(&bso, "%5.2f dwarf\n", cputime()); @@ -918,6 +940,7 @@ asmb(void) Elfput: eh = getElfEhdr(); startva = INITTEXT - HEADR; + resoff = ELFRESERVE; /* This null SHdr must appear before all others */ newElfShdr(elfstr[ElfStrEmpty]); @@ -956,9 +979,15 @@ asmb(void) case Hfreebsd: interpreter = freebsddynld; break; + case Hnetbsd: + interpreter = netbsddynld; + break; + case Hopenbsd: + interpreter = openbsddynld; + break; } } - elfinterp(sh, startva, interpreter); + resoff -= elfinterp(sh, startva, resoff, interpreter); ph = newElfPhdr(); ph->type = PT_INTERP; @@ -966,11 +995,27 @@ asmb(void) phsh(ph, sh); } + if(HEADTYPE == Hnetbsd) { + sh = newElfShdr(elfstr[ElfStrNoteNetbsdIdent]); + sh->type = SHT_NOTE; + sh->flags = SHF_ALLOC; + sh->addralign = 4; + resoff -= elfnetbsdsig(sh, startva, resoff); + + ph = newElfPhdr(); + ph->type = PT_NOTE; + ph->flags = PF_R; + phsh(ph, sh); + } + + // Additions to the reserved area must be above this line. + USED(resoff); + elfphload(&segtext); elfphload(&segdata); /* Dynamic linking sections */ - if (!debug['d']) { /* -d suppresses dynamic loader format */ + if(!debug['d']) { /* -d suppresses dynamic loader format */ /* S headers for dynamic linking */ sh = newElfShdr(elfstr[ElfStrGot]); sh->type = SHT_PROGBITS; @@ -1094,7 +1139,7 @@ asmb(void) for(sect=segdata.sect; sect!=nil; sect=sect->next) elfshbits(sect); - if (!debug['s']) { + if(!debug['s']) { sh = newElfShdr(elfstr[ElfStrSymtab]); sh->type = SHT_SYMTAB; sh->off = symo; @@ -1122,7 +1167,13 @@ asmb(void) eh->ident[EI_VERSION] = EV_CURRENT; switch(HEADTYPE) { case Hfreebsd: - eh->ident[EI_OSABI] = 9; + eh->ident[EI_OSABI] = ELFOSABI_FREEBSD; + break; + case Hnetbsd: + eh->ident[EI_OSABI] = ELFOSABI_NETBSD; + break; + case Hopenbsd: + eh->ident[EI_OSABI] = ELFOSABI_OPENBSD; break; } @@ -1141,8 +1192,10 @@ asmb(void) a += elfwritehdr(); a += elfwritephdrs(); a += elfwriteshdrs(); - cflush(); - if(a+elfwriteinterp() > ELFRESERVE) + a += elfwriteinterp(elfstr[ElfStrInterp]); + if(HEADTYPE == Hnetbsd) + a += elfwritenetbsdsig(elfstr[ElfStrNoteNetbsdIdent]); + if(a > ELFRESERVE) diag("ELFRESERVE too small: %d > %d", a, ELFRESERVE); break; @@ -1205,12 +1258,16 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*)) case SSTRING: case SGOSTRING: case SWINDOWS: + case SNOPTRDATA: + case SSYMTAB: + case SPCLNTAB: if(!s->reachable) continue; put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype); continue; case SBSS: + case SNOPTRBSS: if(!s->reachable) continue; put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype); diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go index b70888907..12301d4f2 100644 --- a/src/cmd/8l/doc.go +++ b/src/cmd/8l/doc.go @@ -4,47 +4,10 @@ /* -8l is a modified version of the Plan 9 linker. The original is documented at - - http://plan9.bell-labs.com/magic/man2html/1/2l - -Its target architecture is the x86, referred to by these tools for historical reasons as 386. -It reads files in .8 format generated by 8g, 8c, and 8a and emits -a binary called 8.out by default. - -Major changes include: - - support for ELF and Mach-O binary files - - support for segmented stacks (this feature is implemented here, not in the compilers). - - -Original options are listed in the link above. - -Options new in this version: - --d - Elide the dynamic linking header. With this option, the binary - is statically linked and does not refer to dynld. Without this option - (the default), the binary's contents are identical but it is loaded with dynld. --Hplan9 - Write Plan 9 32-bit format binaries (default when $GOOS is plan9) --Hdarwin - Write Apple Mach-O binaries (default when $GOOS is darwin) --Hlinux - Write Linux ELF binaries (default when $GOOS is linux) --Hfreebsd - Write FreeBSD ELF binaries (default when $GOOS is freebsd) --Hwindows - Write Windows PE32 binaries (default when $GOOS is windows) --I interpreter - Set the ELF dynamic linker to use. --L dir1 -L dir2 - Search for libraries (package files) in dir1, dir2, etc. - The default is the single location $GOROOT/pkg/$GOOS_386. --r dir1:dir2:... - Set the dynamic linker search path when using ELF. --V - Print the linker version. +8l is the linker for the 32-bit x86. +The $GOARCH for these tools is 386. +The flags are documented in ../ld/doc.go. */ package documentation diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 4ee0db967..b974f464b 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -134,6 +134,7 @@ struct Sym int32 dynid; int32 plt; int32 got; + int32 align; // if non-zero, required alignment in bytes Sym* hash; // in hash table Sym* allsym; // in all symbol list Sym* next; // in text or data list @@ -209,6 +210,7 @@ enum Zbr, Zcall, Zcallcon, + Zcallind, Zib_, Zib_rp, Zibo_m, diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index a8e1c34a5..af4bc844f 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -47,17 +47,19 @@ char *noname = ""; char *thestring = "386"; Header headers[] = { - "garbunix", Hgarbunix, - "unixcoff", Hunixcoff, - "plan9", Hplan9x32, - "msdoscom", Hmsdoscom, - "msdosexe", Hmsdosexe, - "darwin", Hdarwin, - "linux", Hlinux, - "freebsd", Hfreebsd, - "windows", Hwindows, - "windowsgui", Hwindows, - 0, 0 + "garbunix", Hgarbunix, + "unixcoff", Hunixcoff, + "plan9", Hplan9x32, + "msdoscom", Hmsdoscom, + "msdosexe", Hmsdosexe, + "darwin", Hdarwin, + "linux", Hlinux, + "freebsd", Hfreebsd, + "netbsd", Hnetbsd, + "openbsd", Hopenbsd, + "windows", Hwindows, + "windowsgui", Hwindows, + 0, 0 }; /* @@ -69,6 +71,8 @@ Header headers[] = { * -Hdarwin -Tx -Rx is Apple Mach-O * -Hlinux -Tx -Rx is Linux ELF32 * -Hfreebsd -Tx -Rx is FreeBSD ELF32 + * -Hnetbsd -Tx -Rx is NetBSD ELF32 + * -Hopenbsd -Tx -Rx is OpenBSD ELF32 * -Hwindows -Tx -Rx is MS Windows PE32 */ @@ -83,6 +87,7 @@ void main(int argc, char *argv[]) { int c; + char *name, *val; Binit(&bso, 1, OWRITE); listinit(); @@ -94,6 +99,7 @@ main(int argc, char *argv[]) INITDAT = -1; INITRND = -1; INITENTRY = 0; + nuxiinit(); ARGBEGIN { default: @@ -133,6 +139,11 @@ main(int argc, char *argv[]) case 'V': print("%cl version %s\n", thechar, getgoversion()); errorexit(); + case 'X': + name = EARGF(usage()); + val = EARGF(usage()); + addstrdata(name, val); + break; } ARGEND if(argc != 1) @@ -209,7 +220,7 @@ main(int argc, char *argv[]) case Hdarwin: /* apple MACH */ /* * OS X system constant - offset from %gs to our TLS. - * Explained in ../../libcgo/darwin_386.c. + * Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c. */ tlsoffset = 0x468; machoinit(); @@ -223,11 +234,13 @@ main(int argc, char *argv[]) break; case Hlinux: /* elf32 executable */ case Hfreebsd: + case Hnetbsd: + case Hopenbsd: /* * ELF uses TLS offsets negative from %gs. * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS). - * Also known to ../../pkg/runtime/linux/386/sys.s - * and ../../libcgo/linux_386.c. + * Also known to ../../pkg/runtime/sys_linux_386.s + * and ../../pkg/runtime/cgo/gcc_linux_386.c. */ tlsoffset = -8; elfinit(); @@ -269,7 +282,6 @@ main(int argc, char *argv[]) zprg.to = zprg.from; pcstr = "%.6ux "; - nuxiinit(); histgen = 0; pc = 0; dtype = 4; @@ -477,7 +489,7 @@ loop: sig = 1729; if(sig != 0){ if(s->sig != 0 && s->sig != sig) - diag("incompatible type signatures" + diag("incompatible type signatures " "%ux(%s) and %ux(%s) for %s", s->sig, s->file, sig, pn, s->name); s->sig = sig; @@ -551,7 +563,7 @@ loop: s->type = SBSS; s->size = 0; } - if(s->type != SBSS && !s->dupok) { + if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) { diag("%s: redefinition: %s in %s", pn, s->name, TNAME); s->type = SBSS; @@ -563,6 +575,8 @@ loop: s->dupok = 1; if(p->from.scale & RODATA) s->type = SRODATA; + else if(p->from.scale & NOPTR) + s->type = SNOPTRBSS; goto loop; case ADATA: @@ -594,6 +608,10 @@ loop: case ATEXT: s = p->from.sym; if(s->text != nil) { + if(p->from.scale & DUPOK) { + skip = 1; + goto casdef; + } diag("%s: %s: redefinition", pn, s->name); return; } diff --git a/src/cmd/8l/optab.c b/src/cmd/8l/optab.c index f5c195d75..856482290 100644 --- a/src/cmd/8l/optab.c +++ b/src/cmd/8l/optab.c @@ -260,6 +260,7 @@ uchar yloop[] = uchar ycall[] = { Ynone, Yml, Zo_m, 2, + Ynone, Ycol, Zcallind, 2, Ynone, Ybr, Zcall, 0, Ynone, Yi32, Zcallcon, 1, 0 @@ -383,7 +384,7 @@ Optab optab[] = { ABTSL, yml_rl, Pm, 0xab }, { ABTSW, yml_rl, Pq, 0xab }, { ABYTE, ybyte, Px, 1 }, - { ACALL, ycall, Px, 0xff,(02),0xe8 }, + { ACALL, ycall, Px, 0xff,(02),0xff,(0x15),0xe8 }, { ACLC, ynone, Px, 0xf8 }, { ACLD, ynone, Px, 0xfc }, { ACLI, ynone, Px, 0xfa }, @@ -430,7 +431,8 @@ Optab optab[] = { AIRETW, ynone, Pe, 0xcf }, { AJCC, yjcond, Px, 0x73,0x83,(00) }, { AJCS, yjcond, Px, 0x72,0x82 }, - { AJCXZ, yloop, Px, 0xe3 }, + { AJCXZL, yloop, Px, 0xe3 }, + { AJCXZW, yloop, Px, 0xe3 }, { AJEQ, yjcond, Px, 0x74,0x84 }, { AJGE, yjcond, Px, 0x7d,0x8d }, { AJGT, yjcond, Px, 0x7f,0x8f }, @@ -705,6 +707,8 @@ Optab optab[] = { ACMPXCHGW, yrl_ml, Pm, 0xb1 }, { ACMPXCHG8B, yscond, Pm, 0xc7,(01) }, + { ARDTSC, ynone, Pm, 0x31 }, + { AXADDB, yrb_mb, Pb, 0x0f,0xc0 }, { AXADDL, yrl_ml, Pm, 0xc1 }, { AXADDW, yrl_ml, Pe, 0x0f,0xc1 }, @@ -751,5 +755,11 @@ Optab optab[] = { AFCMOVNU, yfcmv, Px, 0xdb,(03) }, { AFCMOVUN, yfcmv, Px, 0xda,(03) }, + { ALFENCE, ynone, Pm, 0xae,0xe8 }, + { AMFENCE, ynone, Pm, 0xae,0xf0 }, + { ASFENCE, ynone, Pm, 0xae,0xf8 }, + + { AEMMS, ynone, Pm, 0x77 }, + 0 }; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index 2e0990c5a..9034fdf3a 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -259,7 +259,7 @@ patch(void) // Convert // op n(GS), reg // to - // MOVL 0x2C(FS), reg + // MOVL 0x14(FS), reg // op n(reg), reg // The purpose of this patch is to fix some accesses // to extern register variables (TLS) on Windows, as @@ -273,7 +273,7 @@ patch(void) q->as = p->as; p->as = AMOVL; p->from.type = D_INDIR+D_FS; - p->from.offset = 0x2C; + p->from.offset = 0x14; } } if(HEADTYPE == Hlinux) { @@ -307,9 +307,12 @@ patch(void) p->from.offset = 0; } } - if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH)) { + if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH)) { s = p->to.sym; - if(s) { + if(p->to.type == D_INDIR+D_ADDR) { + /* skip check if this is an indirect call (CALL *symbol(SB)) */ + continue; + } else if(s) { if(debug['c']) Bprint(&bso, "%s calls %s\n", TNAME, s->name); if((s->type&~SSUB) != STEXT) { @@ -421,7 +424,7 @@ dostkoff(void) case Hwindows: p->as = AMOVL; p->from.type = D_INDIR+D_FS; - p->from.offset = 0x2c; + p->from.offset = 0x14; p->to.type = D_CX; p = appendp(p); @@ -524,10 +527,18 @@ dostkoff(void) p = appendp(p); // save frame size in DX p->as = AMOVL; p->to.type = D_DX; - /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ p->from.type = D_CONST; - if(autoffset+160+cursym->text->to.offset2 > 4096) - p->from.offset = (autoffset+160) & ~7LL; + + // If we ask for more stack, we'll get a minimum of StackMin bytes. + // We need a stack frame large enough to hold the top-of-stack data, + // the function arguments+results, our caller's PC, our frame, + // a word for the return PC of the next call, and then the StackLimit bytes + // that must be available on entry to any function called from a function + // that did a stack check. If StackMin is enough, don't ask for a specific + // amount: then we can use the custom functions and save a few + // instructions. + if(StackTop + cursym->text->to.offset2 + PtrSize + autoffset + PtrSize + StackLimit >= StackMin) + p->from.offset = (autoffset+7) & ~7LL; p = appendp(p); // save arg size in AX p->as = AMOVL; diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index a4cba1257..81c1d37eb 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -83,7 +83,10 @@ span1(Sym *s) loop++; q->back ^= 2; } - s->p[q->pc+1] = v; + if(q->as == AJCXZW) + s->p[q->pc+2] = v; + else + s->p[q->pc+1] = v; } else { bp = s->p + q->pc + q->mark - 4; *bp++ = v; @@ -282,6 +285,8 @@ oclass(Adr *a) } return Yxxx; } + //if(a->type == D_INDIR+D_ADDR) + // print("*Ycol\n"); return Ycol; } return Ym; @@ -1056,9 +1061,10 @@ found: case Zbr: case Zjmp: + case Zloop: q = p->pcond; if(q == nil) { - diag("jmp/branch without target"); + diag("jmp/branch/loop without target"); errorexit(); } if(q->as == ATEXT) { @@ -1084,8 +1090,12 @@ found: if(p->back & 1) { v = q->pc - (p->pc + 2); if(v >= -128) { + if(p->as == AJCXZW) + *andptr++ = 0x67; *andptr++ = op; *andptr++ = v; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); } else { v -= 5-2; if(t[2] == Zbr) { @@ -1105,8 +1115,12 @@ found: p->forwd = q->comefrom; q->comefrom = p; if(p->back & 2) { // short + if(p->as == AJCXZW) + *andptr++ = 0x67; *andptr++ = op; *andptr++ = 0; + } else if(t[2] == Zloop) { + diag("loop too far: %P", p); } else { if(t[2] == Zbr) *andptr++ = 0x0f; @@ -1131,18 +1145,17 @@ found: r->add = p->to.offset; put4(0); break; - - case Zloop: - q = p->pcond; - if(q == nil) { - diag("loop without target"); - errorexit(); - } - v = q->pc - p->pc - 2; - if(v < -128 && v > 127) - diag("loop too far: %P", p); + + case Zcallind: *andptr++ = op; - *andptr++ = v; + *andptr++ = o->op[z+1]; + r = addrel(cursym); + r->off = p->pc + andptr - and; + r->type = D_ADDR; + r->siz = 4; + r->add = p->to.offset; + r->sym = p->to.sym; + put4(0); break; case Zbyte: -- cgit v1.2.3