liblink: create new library based on linker code

There is an enormous amount of code moving around in this CL,
but the code is the same, and it is invoked in the same ways.
This CL is preparation for the new linker structure, not the new
structure itself.

The new library's definition is in include/link.h.

The main change is the use of a Link structure to hold all the
linker-relevant state, replacing the smattering of global variables.
The Link structure should both make it clearer which state must
be carried around and make it possible to parallelize more easily
later.

The main body of the linker has moved into the architecture-independent
cmd/ld directory. That includes the list of known header types, so the
distinction between Hplan9x32 and Hplan9x64 is removed (no other
header type distinguished 32- and 64-bit formats), and code for unused
formats such as ipaq kernels has been deleted.

The code being deleted from 5l, 6l, and 8l reappears in liblink or in ld.
Because multiple files are being merged in the liblink directory,
it is not possible to show the diffs nicely in hg.

The Prog and Addr structures have been unified into an
architecture-independent form and moved to link.h, where they will
be shared by all tools: the assemblers, the compilers, and the linkers.
The unification makes it possible to write architecture-independent
traversal of Prog lists, among other benefits.

The Sym structures cannot be unified: they are too fundamentally
different between the linker and the compilers. Instead, liblink defines
an LSym - a linker Sym - to be used in the Prog and Addr structures,
and the linker now refers exclusively to LSyms. The compilers will
keep using their own syms but will fill out the corresponding LSyms in
the Prog and Addr structures.

Although code from 5l, 6l, and 8l is now in a single library, the
code has been arranged so that only one architecture needs to
be linked into a particular program: 5l will not contain the code
needed for x86 instruction layout, for example.

The object file writing code in liblink/obj.c is from cmd/gc/obj.c.

Preparation for golang.org/s/go13linker work.

This CL does not build by itself. It depends on 35740044
and will be submitted at the same time.

R=iant
CC=golang-dev
https://golang.org/cl/35790044
This commit is contained in:
Russ Cox 2013-12-08 22:49:37 -05:00
parent 8642cbd660
commit 7d507dc6e6
67 changed files with 17385 additions and 17705 deletions

567
include/link.h Normal file
View file

@ -0,0 +1,567 @@
// Derived from Inferno utils/6l/l.h and related files.
// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
//
// 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.
typedef struct Addr Addr;
typedef struct Prog Prog;
typedef struct LSym LSym;
typedef struct Reloc Reloc;
typedef struct Auto Auto;
typedef struct Hist Hist;
typedef struct Hist2 Hist2;
typedef struct Link Link;
typedef struct Plist Plist;
typedef struct LinkArch LinkArch;
typedef struct Library Library;
typedef struct Pcln Pcln;
typedef struct Pcdata Pcdata;
struct Addr
{
vlong offset;
union
{
char sval[8];
float64 dval;
Prog* branch; // for 5g, 6g, 8g
} u;
LSym* sym;
LSym* gotype;
short type;
uint8 index;
int8 scale;
int8 reg; // for 5l
int8 name; // for 5l
int8 class; // for 5l
uint8 etype; // for 5g, 6g, 8g
int32 offset2; // for 5l, 8l
struct Node* node; // for 5g, 6g, 8g
int64 width; // for 5g, 6g, 8g
};
struct Reloc
{
int32 off;
uchar siz;
uchar done;
int32 type;
int64 add;
int64 xadd;
LSym* sym;
LSym* xsym;
};
struct Prog
{
vlong pc;
int32 lineno;
Prog* link;
short as;
uchar reg; // arm only
uchar scond; // arm only
Addr from;
Addr to;
// for 5g, 6g, 8g internal use
uint32 loc; // TODO: merge with pc?
void* opt;
// for 5l, 6l, 8l internal use
Prog* forwd;
Prog* pcond;
Prog* comefrom; // 6l, 8l
Prog* pcrel; // 5l
int32 spadj;
uchar mark;
uchar back; // 6l, 8l
char ft; /* 6l, 8l oclass cache */
char tt; // 6l, 8l
uchar optab; // 5l
char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
struct LSym
{
char* name;
char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
uchar leaf; // arm only
uchar fnptr; // arm only
int16 symid; // for writing .5/.6/.8 files
int32 dynid;
int32 sig;
int32 plt;
int32 got;
int32 align; // if non-zero, required alignment in bytes
int32 elfsym;
int32 args; // size of stack frame incoming arguments area
int32 locals; // size of stack frame locals area (arm only?)
vlong value;
vlong size;
LSym* hash; // in hash table
LSym* allsym; // in all symbol list
LSym* next; // in text or data list
LSym* sub; // in SSUB list
LSym* outer; // container of sub
LSym* gotype;
LSym* reachparent;
LSym* queue;
char* file;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
Hist2* hist; // for ATEXT
// STEXT
Auto* autom;
Prog* text;
Pcln* pcln;
// SDATA, SBSS
uchar* p;
int32 np;
int32 maxp;
Reloc* r;
int32 nr;
int32 maxr;
};
// LSym.type
enum
{
Sxxx,
/* order here is order in output file */
/* readonly, executable */
STEXT,
SELFRXSECT,
/* readonly, non-executable */
STYPE,
SSTRING,
SGOSTRING,
SGOFUNC,
SRODATA,
SFUNCTAB,
STYPELINK,
SSYMTAB, // TODO: move to unmapped section
SPCLNTAB,
SELFROSECT,
/* writable, non-executable */
SMACHOPLT,
SELFSECT,
SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT,
SNOPTRDATA,
SINITARR,
SDATA,
SWINDOWS,
SBSS,
SNOPTRBSS,
STLSBSS,
/* not mapped */
SXREF,
SMACHOSYMSTR,
SMACHOSYMTAB,
SMACHOINDIRECTPLT,
SMACHOINDIRECTGOT,
SFILE,
SFILEPATH,
SCONST,
SDYNIMPORT,
SHOSTOBJ,
SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
SMASK = SSUB - 1,
SHIDDEN = 1<<9, // hidden or local symbol
};
struct Auto
{
LSym* asym;
Auto* link;
int32 aoffset;
int16 type;
LSym* gotype;
};
enum
{
LINKHASH = 100003,
};
struct Hist
{
Hist* link;
char* name;
int32 line;
int32 offset;
};
struct Plist
{
LSym* name;
Prog* firstpc;
int recur;
Plist* link;
};
struct Library
{
char *objref; // object where we found the reference
char *srcref; // src file where we found the reference
char *file; // object file
char *pkg; // import path
};
struct Pcdata
{
uchar *p;
int n;
int m;
};
struct Pcln
{
Pcdata pcsp;
Pcdata pcfile;
Pcdata pcline;
Pcdata *pcdata;
int npcdata;
LSym **funcdata;
int64 *funcdataoff;
int nfuncdata;
LSym **file;
int nfile;
int mfile;
LSym *lastfile;
int lastindex;
};
enum
{
LinkMaxHist = 40,
};
// TODO: Replace uses of Hist2 with Hist and delete this.
struct Hist2
{
int32 line;
int32 off;
LSym *file;
};
// symbol version, incremented each time a file is loaded.
// version==1 is reserved for savehist.
enum
{
HistVersion = 1,
};
// Link holds the context for writing object code from a compiler
// to be linker input or for reading that input into the linker.
struct Link
{
int32 thechar; // '5' (arm), '6' (amd64), etc.
char* thestring; // full name of architecture ("arm", "amd64", ..)
int32 goarm; // for arm only, GOARM setting
int headtype;
int linkmode;
LinkArch* arch;
int32 (*ignore)(char*); // do not emit names satisfying this function
int32 debugasm; // -S flag in compiler
int32 debugline; // -L flag in compiler
int32 debughist; // -O flag in linker
int32 debugread; // -W flag in linker
int32 debugvlog; // -v flag in linker
int32 debugstack; // -K flag in linker
int32 debugzerostack; // -Z flag in linker
int32 debugdivmod; // -M flag in 5l
int32 debugfloat; // -F flag in 5l
int32 debugpcln; // -O flag in linker
int32 flag_shared; // -shared flag in linker
int32 iself;
Biobuf* bso; // for -v flag
char* pathname;
int32 windows;
// hash table of all symbols
LSym* hash[LINKHASH];
LSym* allsym;
int32 nsymbol;
// file-line history
Hist* hist;
Hist* ehist;
// all programs
Plist* plist;
Plist* plast;
// code generation
LSym* sym_div;
LSym* sym_divu;
LSym* sym_mod;
LSym* sym_modu;
LSym* symmorestack[10];
LSym* gmsym;
LSym* plan9tos;
Prog* curp;
Prog* printp;
Prog* blitrl;
Prog* elitrl;
int rexflag;
int asmode;
uchar* andptr;
uchar and[100];
int32 instoffset;
int32 autosize;
int32 armsize;
// for reading input files (during linker)
vlong pc;
char** libdir;
int32 nlibdir;
int32 maxlibdir;
Library* library;
int libraryp;
int nlibrary;
int tlsoffset;
void (*diag)(char*, ...);
void (*dwarfaddfrag)(int, char*);
LSym* histfrog[LinkMaxHist];
int histfrogp;
int histgen;
Auto* curauto;
Auto* curhist;
LSym* cursym;
int version;
LSym* textp;
LSym* etextp;
Hist2* histcopy;
Hist2* hist2;
int32 nhist2;
int32 maxhist2;
int32 histdepth;
int32 nhistfile;
LSym* filesyms;
};
// LinkArch is the definition of a single architecture.
struct LinkArch
{
char* name; // "arm", "amd64", and so on
void (*addstacksplit)(Link*, LSym*);
void (*assemble)(Link*, LSym*);
int (*datasize)(Prog*);
void (*follow)(Link*, LSym*);
int (*iscall)(Prog*);
int (*isdata)(Prog*);
void (*ldobj)(Link*, Biobuf*, char*, int64, char*);
void (*nopout)(Prog*);
Prog* (*prg)(void);
void (*progedit)(Link*, Prog*);
void (*settextflag)(Prog*, int);
int (*symtype)(Addr*);
int (*textflag)(Prog*);
void (*zfile)(Biobuf*, char*, int);
void (*zhist)(Biobuf*, int, vlong);
void (*zprog)(Link*, Biobuf*, Prog*, int, int, int, int);
void (*zname)(Biobuf*, LSym*, int);
int minlc;
int ptrsize;
// TODO: Give these the same values on all systems.
int D_ADDR;
int D_BRANCH;
int D_CONST;
int D_EXTERN;
int D_FCONST;
int D_NONE;
int D_PCREL;
int D_SCONST;
int D_SIZE;
int ACALL;
int AFUNCDATA;
int AJMP;
int ANOP;
int APCDATA;
int ARET;
int ATEXT;
int AUSEFIELD;
};
/* executable header types */
enum {
Hunknown = 0,
Hdarwin,
Hdragonfly,
Helf,
Hfreebsd,
Hlinux,
Hnetbsd,
Hopenbsd,
Hplan9,
Hwindows,
};
enum
{
LinkAuto = 0,
LinkInternal,
LinkExternal,
};
extern uchar fnuxi8[8];
extern uchar fnuxi4[4];
extern uchar inuxi1[1];
extern uchar inuxi2[2];
extern uchar inuxi4[4];
extern uchar inuxi8[8];
// asm5.c
void span5(Link *ctxt, LSym *s);
// asm6.c
void span6(Link *ctxt, LSym *s);
// asm8.c
void span8(Link *ctxt, LSym *s);
// data.c
vlong addaddr(Link *ctxt, LSym *s, LSym *t);
vlong addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add);
vlong addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add);
vlong addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add);
Reloc* addrel(LSym *s);
vlong addsize(Link *ctxt, LSym *s, LSym *t);
vlong adduint16(Link *ctxt, LSym *s, uint16 v);
vlong adduint32(Link *ctxt, LSym *s, uint32 v);
vlong adduint64(Link *ctxt, LSym *s, uint64 v);
vlong adduint8(Link *ctxt, LSym *s, uint8 v);
vlong adduintxx(Link *ctxt, LSym *s, uint64 v, int wid);
void mangle(char *file);
void savedata(Link *ctxt, LSym *s, Prog *p, char *pn);
vlong setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
vlong setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
vlong setuint16(Link *ctxt, LSym *s, vlong r, uint16 v);
vlong setuint32(Link *ctxt, LSym *s, vlong r, uint32 v);
vlong setuint64(Link *ctxt, LSym *s, vlong r, uint64 v);
vlong setuint8(Link *ctxt, LSym *s, vlong r, uint8 v);
vlong setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid);
void symgrow(Link *ctxt, LSym *s, int32 siz);
// go.c
void* emallocz(long n);
void* erealloc(void *p, long n);
char* estrdup(char *p);
char* expandpkg(char *t0, char *pkg);
// ieee.c
void double2ieee(uint64 *ieee, double native);
// ld.c
void addhist(Link *ctxt, int32 line, int type);
void addlib(Link *ctxt, char *src, char *obj);
void addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg);
void collapsefrog(Link *ctxt, LSym *s);
void copyhistfrog(Link *ctxt, char *buf, int nbuf);
int find1(int32 l, int c);
Hist2* gethist(Link *ctxt);
void linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l);
void histtoauto(Link *ctxt);
void mkfwd(LSym*);
void nuxiinit(void);
void savehist(Link *ctxt, int32 line, int32 off);
Prog* copyp(Link*, Prog*);
Prog* appendp(Link*, Prog*);
vlong atolwhex(char*);
// obj.c
int linklinefmt(Link *ctxt, Fmt *fp);
void linklinehist(Link *ctxt, int lineno, char *f, int offset);
Plist* linknewplist(Link *ctxt);
void linkouthist(Link *ctxt, Biobuf *b);
void linkprfile(Link *ctxt, int32 l);
void linkwritefuncs(Link *ctxt, Biobuf *b);
// pass.c
Prog* brchain(Link *ctxt, Prog *p);
Prog* brloop(Link *ctxt, Prog *p);
void linkpatch(Link *ctxt, LSym *sym);
// pcln.c
void linkpcln(Link*, LSym*);
// rdobj5.c
void ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout5(Prog *p);
// rdobj6.c
void ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout6(Prog *p);
// rdobj8.c
void ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn);
void nopout8(Prog *p);
// sym.c
LSym* linklookup(Link *ctxt, char *name, int v);
Link* linknew(LinkArch*);
LSym* linknewsym(Link *ctxt, char *symb, int v);
LSym* linkrlookup(Link *ctxt, char *name, int v);
int linksymfmt(Fmt *f);
extern char* anames5[];
extern char* anames6[];
extern char* anames8[];
extern LinkArch link386;
extern LinkArch linkamd64;
extern LinkArch linkarm;

View file

@ -188,6 +188,8 @@ typedef u32int uint32;
typedef s64int int64;
typedef u64int uint64;
typedef float float32;
typedef double float64;
#undef _NEEDUCHAR
#undef _NEEDUSHORT

View file

@ -234,62 +234,53 @@ 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)
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),
#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)
D_SHIFT = (D_NONE+19),
D_FPCR = (D_NONE+20),
D_REGREG = (D_NONE+21), // (reg, reg)
D_ADDR = (D_NONE+22),
#define D_SBIG (D_NONE+23)
#define D_CONST2 (D_NONE+24)
D_SBIG = (D_NONE+23),
D_CONST2 = (D_NONE+24),
#define D_REGREG2 (D_NONE+25) // reg, reg
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)
D_EXTERN = (D_NONE+3),
D_STATIC = (D_NONE+4),
D_AUTO = (D_NONE+5),
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_SIZE = (D_NONE+40),
D_PCREL = (D_NONE+41),
D_GOTOFF = (D_NONE+42), // R_ARM_GOTOFF
D_PLT0 = (D_NONE+43), // R_ARM_PLT32, 1st inst: add ip, pc, #0xNN00000
D_PLT1 = (D_NONE+44), // R_ARM_PLT32, 2nd inst: add ip, ip, #0xNN000
D_PLT2 = (D_NONE+45), // R_ARM_PLT32, 3rd inst: ldr pc, [ip, #0xNNN]!
D_CALL = (D_NONE+46), // R_ARM_PLT32/R_ARM_CALL/R_ARM_JUMP24, bl xxxxx or b yyyyy
D_TLS = (D_NONE+47), // R_ARM_TLS_LE32
};
/*
* 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 */
};

File diff suppressed because it is too large Load diff

View file

@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "5.out.h"
enum
@ -51,167 +52,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 +67,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 +114,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 +124,61 @@ 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;
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 "D" Addr*
#pragma varargck type "I" uchar*
#pragma varargck type "N" Adr*
#pragma varargck type "N" Addr*
#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 Aconv(Fmt *fp);
int Cconv(Fmt *fp);
int Dconv(Fmt *fp);
int Iconv(Fmt *fp);
int Nconv(Fmt *fp);
int Oconv(Fmt *fp);
int Pconv(Fmt *fp);
int Sconv(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);
void diag(char *fmt, ...);
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)

View file

@ -47,11 +47,7 @@ listinit(void)
fmtinstall('I', Iconv);
}
void
prasm(Prog *p)
{
print("%P\n", p);
}
static Prog *curp;
int
Pconv(Fmt *fp)
@ -64,7 +60,7 @@ Pconv(Fmt *fp)
a = p->as;
switch(a) {
default:
fmtprint(fp, "(%d)", p->line);
fmtprint(fp, "(%d)", p->lineno);
if(p->reg == NREG && p->as != AGLOBL)
fmtprint(fp, " %A%C %D,%D",
a, p->scond, &p->from, &p->to);
@ -80,22 +76,22 @@ Pconv(Fmt *fp)
case ASWPW:
case ASWPBU:
fmtprint(fp, "(%d) %A%C R%d,%D,%D",
p->line, a, p->scond, p->reg, &p->from, &p->to);
p->lineno, 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);
p->lineno, a, p->scond, &p->from, p->reg, &p->to);
break;
case AWORD:
fmtprint(fp, "(%d) WORD %D", p->line, &p->to);
fmtprint(fp, "(%d) WORD %D", p->lineno, &p->to);
break;
case ADWORD:
fmtprint(fp, "(%d) DWORD %D %D", p->line, &p->from, &p->to);
fmtprint(fp, "(%d) DWORD %D %D", p->lineno, &p->from, &p->to);
break;
}
@ -114,7 +110,7 @@ Aconv(Fmt *fp)
a = va_arg(fp->args, int);
s = "???";
if(a >= AXXX && a < ALAST)
s = anames[a];
s = anames5[a];
return fmtstrcpy(fp, s);
}
@ -162,10 +158,10 @@ Dconv(Fmt *fp)
{
char str[STRINGSZ];
const char *op;
Adr *a;
Addr *a;
int32 v;
a = va_arg(fp->args, Adr*);
a = va_arg(fp->args, Addr*);
switch(a->type) {
default:
@ -271,8 +267,8 @@ Dconv(Fmt *fp)
break;
case D_BRANCH: /* botch */
if(curp->cond != P) {
v = curp->cond->pc;
if(curp->pcond != P) {
v = curp->pcond->pc;
if(a->sym != S)
snprint(str, sizeof str, "%s+%.5ux(BRANCH)", a->sym->name, v);
else
@ -285,11 +281,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
snprint(str, sizeof str, "$%e", ieeedtod(&a->ieee));
snprint(str, sizeof str, "$%.17g", a->u.dval);
break;
case D_SCONST:
snprint(str, sizeof str, "$\"%S\"", a->sval);
snprint(str, sizeof str, "$\"%S\"", a->u.sval);
break;
}
return fmtstrcpy(fp, str);
@ -299,10 +295,10 @@ int
Nconv(Fmt *fp)
{
char str[STRINGSZ];
Adr *a;
Sym *s;
Addr *a;
LSym *s;
a = va_arg(fp->args, Adr*);
a = va_arg(fp->args, Addr*);
s = a->sym;
switch(a->name) {
default:
@ -478,8 +474,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
if(cursym != S) {
tn = cursym->name;
if(ctxt->cursym != S) {
tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);

View file

@ -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;
LSym *s;
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;
}
/* 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);
}

View file

@ -30,120 +30,19 @@
// 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[])
archinit(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);
LSym *s;
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
@ -161,31 +60,11 @@ main(int argc, char *argv[])
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,29 +73,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:
debug['d'] = 0; // with dynamic linking
tlsoffset = -8; // hardcoded number, first 4-byte word for g, and then 4-byte word for m
ctxt->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;
@ -231,578 +92,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 = linklookup(ctxt, "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;
adduint8(ctxt, s, goarm);
}

View file

@ -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 },
};

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
*/

View file

@ -891,15 +891,3 @@ enum
* 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 */
};

View file

@ -47,46 +47,18 @@ char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
char zeroes[32];
vlong
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;
}
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 %#llx", addr);
return 0;
}
static int
needlib(char *name)
{
char *p;
Sym *s;
LSym *s;
if(*name == '\0')
return 0;
/* reuse hash code in symbol table */
p = smprint(".elfload.%s", name);
s = lookup(p, 0);
s = linklookup(ctxt, p, 0);
free(p);
if(s->type == 0) {
s->type = 100; // avoid SDATA, etc.
@ -97,24 +69,24 @@ needlib(char *name)
int nelfsym = 1;
static void addpltsym(Sym*);
static void addgotsym(Sym*);
static void addpltsym(LSym*);
static void addgotsym(LSym*);
void
adddynrela(Sym *rela, Sym *s, Reloc *r)
adddynrela(LSym *rela, LSym *s, Reloc *r)
{
addaddrplus(rela, s, r->off);
adduint64(rela, R_X86_64_RELATIVE);
addaddrplus(rela, r->sym, r->add); // Addend
addaddrplus(ctxt, rela, s, r->off);
adduint64(ctxt, rela, R_X86_64_RELATIVE);
addaddrplus(ctxt, rela, r->sym, r->add); // Addend
}
void
adddynrel(Sym *s, Reloc *r)
adddynrel(LSym *s, Reloc *r)
{
Sym *targ, *rela, *got;
LSym *targ, *rela, *got;
targ = r->sym;
cursym = s;
ctxt->cursym = s;
switch(r->type) {
default:
@ -139,7 +111,7 @@ adddynrel(Sym *s, Reloc *r)
r->add += 4;
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@ -159,7 +131,7 @@ adddynrel(Sym *s, Reloc *r)
}
addgotsym(targ);
r->type = D_PCREL;
r->sym = lookup(".got", 0);
r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
r->add += targ->got;
return;
@ -183,7 +155,7 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
r->type = D_PCREL;
return;
@ -217,7 +189,7 @@ adddynrel(Sym *s, Reloc *r)
diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
addgotsym(targ);
r->type = D_PCREL;
r->sym = lookup(".got", 0);
r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
return;
}
@ -229,7 +201,7 @@ adddynrel(Sym *s, Reloc *r)
switch(r->type) {
case D_PCREL:
addpltsym(targ);
r->sym = lookup(".plt", 0);
r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
@ -237,14 +209,14 @@ adddynrel(Sym *s, Reloc *r)
if(s->type != SDATA)
break;
if(iself) {
adddynsym(targ);
rela = lookup(".rela", 0);
addaddrplus(rela, s, r->off);
adddynsym(ctxt, targ);
rela = linklookup(ctxt, ".rela", 0);
addaddrplus(ctxt, rela, s, r->off);
if(r->siz == 8)
adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
else
adduint64(rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
adduint64(rela, r->add);
adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
adduint64(ctxt, rela, r->add);
r->type = 256; // ignore during relocsym
return;
}
@ -259,22 +231,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
adddynsym(targ);
got = lookup(".got", 0);
adddynsym(ctxt, targ);
got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
adduint64(got, 0);
adduint32(lookup(".linkedit.got", 0), targ->dynid);
adduint64(ctxt, got, 0);
adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
cursym = s;
ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@ -325,7 +297,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
Sym *rs;
LSym *rs;
rs = r->xsym;
@ -379,7 +351,7 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(r);
USED(s);
@ -390,68 +362,68 @@ archreloc(Reloc *r, Sym *s, vlong *val)
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) {
// pushq got+8(IP)
adduint8(plt, 0xff);
adduint8(plt, 0x35);
addpcrelplus(plt, got, 8);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x35);
addpcrelplus(ctxt, plt, got, 8);
// jmpq got+16(IP)
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addpcrelplus(plt, got, 16);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addpcrelplus(ctxt, plt, got, 16);
// nopl 0(AX)
adduint32(plt, 0x00401f0f);
adduint32(ctxt, plt, 0x00401f0f);
// assume got->size == 0 too
addaddrplus(got, lookup(".dynamic", 0), 0);
adduint64(got, 0);
adduint64(got, 0);
addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
adduint64(ctxt, got, 0);
adduint64(ctxt, got, 0);
}
}
static void
addpltsym(Sym *s)
addpltsym(LSym *s)
{
if(s->plt >= 0)
return;
adddynsym(s);
adddynsym(ctxt, s);
if(iself) {
Sym *plt, *got, *rela;
LSym *plt, *got, *rela;
plt = lookup(".plt", 0);
got = lookup(".got.plt", 0);
rela = lookup(".rela.plt", 0);
plt = linklookup(ctxt, ".plt", 0);
got = linklookup(ctxt, ".got.plt", 0);
rela = linklookup(ctxt, ".rela.plt", 0);
if(plt->size == 0)
elfsetupplt();
// jmpq *got+size(IP)
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addpcrelplus(plt, got, got->size);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addpcrelplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
addaddrplus(got, plt, plt->size);
addaddrplus(ctxt, got, plt, plt->size);
// pushq $x
adduint8(plt, 0x68);
adduint32(plt, (got->size-24-8)/8);
adduint8(ctxt, plt, 0x68);
adduint32(ctxt, plt, (got->size-24-8)/8);
// jmpq .plt
adduint8(plt, 0xe9);
adduint32(plt, -(plt->size+4));
adduint8(ctxt, plt, 0xe9);
adduint32(ctxt, plt, -(plt->size+4));
// rela
addaddrplus(rela, got, got->size-8);
adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
adduint64(rela, 0);
addaddrplus(ctxt, rela, got, got->size-8);
adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
adduint64(ctxt, rela, 0);
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
@ -465,53 +437,53 @@ addpltsym(Sym *s)
// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
// has details about what we're avoiding.
Sym *plt;
LSym *plt;
addgotsym(s);
plt = lookup(".plt", 0);
plt = linklookup(ctxt, ".plt", 0);
adduint32(lookup(".linkedit.plt", 0), s->dynid);
adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addpcrelplus(plt, lookup(".got", 0), s->got);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
static void
addgotsym(Sym *s)
addgotsym(LSym *s)
{
Sym *got, *rela;
LSym *got, *rela;
if(s->got >= 0)
return;
adddynsym(s);
got = lookup(".got", 0);
adddynsym(ctxt, s);
got = linklookup(ctxt, ".got", 0);
s->got = got->size;
adduint64(got, 0);
adduint64(ctxt, got, 0);
if(iself) {
rela = lookup(".rela", 0);
addaddrplus(rela, got, s->got);
adduint64(rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
adduint64(rela, 0);
rela = linklookup(ctxt, ".rela", 0);
addaddrplus(ctxt, rela, got, s->got);
adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
adduint64(ctxt, rela, 0);
} else if(HEADTYPE == Hdarwin) {
adduint32(lookup(".linkedit.got", 0), s->dynid);
adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
adddynsym(Sym *s)
adddynsym(Link *ctxt, LSym *s)
{
Sym *d;
LSym *d;
int t;
char *name;
@ -521,24 +493,24 @@ adddynsym(Sym *s)
if(iself) {
s->dynid = nelfsym++;
d = lookup(".dynsym", 0);
d = linklookup(ctxt, ".dynsym", 0);
name = s->extname;
adduint32(d, addstring(lookup(".dynstr", 0), name));
adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
/* type */
t = STB_GLOBAL << 4;
if(s->cgoexport && (s->type&SMASK) == STEXT)
t |= STT_FUNC;
else
t |= STT_OBJECT;
adduint8(d, t);
adduint8(ctxt, d, t);
/* reserved */
adduint8(d, 0);
adduint8(ctxt, d, 0);
/* section where symbol is defined */
if(s->type == SDYNIMPORT)
adduint16(d, SHN_UNDEF);
adduint16(ctxt, d, SHN_UNDEF);
else {
switch(s->type) {
default:
@ -555,21 +527,21 @@ adddynsym(Sym *s)
t = 14;
break;
}
adduint16(d, t);
adduint16(ctxt, d, t);
}
/* value */
if(s->type == SDYNIMPORT)
adduint64(d, 0);
adduint64(ctxt, d, 0);
else
addaddr(d, s);
addaddr(ctxt, d, s);
/* size of object */
adduint64(d, s->size);
adduint64(ctxt, d, s->size);
if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
elfwritedynent(lookup(".dynamic", 0), DT_NEEDED,
addstring(lookup(".dynstr", 0), s->dynimplib));
elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@ -583,16 +555,16 @@ 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 if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else {
@ -607,7 +579,7 @@ asmb(void)
int i;
vlong vl, symo, dwarfoff, machlink;
Section *sect;
Sym *sym;
LSym *sym;
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
@ -662,8 +634,7 @@ asmb(void)
switch(HEADTYPE) {
default:
diag("unknown header type %d", HEADTYPE);
case Hplan9x32:
case Hplan9x64:
case Hplan9:
case Helf:
break;
case Hdarwin:
@ -690,7 +661,7 @@ asmb(void)
Bflush(&bso);
switch(HEADTYPE) {
default:
case Hplan9x64:
case Hplan9:
case Helf:
debug['s'] = 1;
symo = HEADR+segtext.len+segdata.filelen;
@ -729,11 +700,11 @@ asmb(void)
elfemitreloc();
}
break;
case Hplan9x64:
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++)
@ -761,7 +732,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
case Hplan9x64: /* plan9 */
case Hplan9: /* plan9 */
magic = 4*26*26+7;
magic |= 0x00008000; /* fat header */
lputb(magic); /* magic */
@ -775,17 +746,6 @@ asmb(void)
lputb(lcsize); /* line offsets */
vputb(vl); /* va of entry */
break;
case Hplan9x32: /* plan9 */
magic = 4*26*26+7;
lputb(magic); /* magic */
lputb(segtext.filelen); /* sizes */
lputb(segdata.filelen);
lputb(segdata.len - segdata.filelen);
lputb(symsize); /* nsyms */
lputb(entryvalue()); /* va of entry */
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
case Hdarwin:
asmbmacho();
break;

View file

@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "6.out.h"
#ifndef EXTERN
@ -64,146 +65,8 @@ enum
};
#define P ((Prog*)0)
#define S ((Sym*)0)
#define TNAME (cursym?cursym->name:noname)
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Movtab Movtab;
typedef struct Reloc Reloc;
struct Adr
{
union
{
vlong u0offset;
char u0scon[8];
Prog *u0cond; /* not used, but should be D_BRANCH */
Ieee u0ieee;
char *u0sbig;
} u0;
Sym* sym;
short type;
char index;
char scale;
};
#define offset u0.u0offset
#define scon u0.u0scon
#define cond u0.u0cond
#define ieee u0.u0ieee
#define sbig u0.u0sbig
struct Reloc
{
int32 off;
uchar siz;
uchar done;
int32 type;
int64 add;
int64 xadd;
Sym* sym;
Sym* xsym;
};
struct Prog
{
Adr from;
Adr to;
Prog* forwd;
Prog* comefrom;
Prog* link;
Prog* pcond; /* work on this */
vlong pc;
int32 spadj;
int32 line;
short as;
char ft; /* oclass cache */
char tt;
uchar mark; /* work on these */
uchar back;
char width; /* fake for DATA */
char mode; /* 16, 32, or 64 */
};
#define datasize from.scale
#define textflag from.scale
#define iscall(p) ((p)->as == ACALL)
struct Auto
{
Sym* asym;
Auto* link;
int32 aoffset;
short type;
Sym* gotype;
};
struct Sym
{
char* name;
char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
int32 dynid;
int32 sig;
int32 plt;
int32 got;
int32 align; // if non-zero, required alignment in bytes
int32 elfsym;
int32 args; // size of stack frame incoming arguments area
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* reachparent;
Sym* queue;
vlong value;
vlong size;
Sym* gotype;
char* file;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
struct Hist* hist; // for ATEXT
// STEXT
Auto* autom;
Prog* text;
// SDATA, SBSS
uchar* p;
int32 np;
int32 maxp;
Reloc* r;
int32 nr;
int32 maxr;
};
struct Optab
{
short as;
uchar* ytab;
uchar prefix;
uchar op[23];
};
struct Movtab
{
short as;
uchar ft;
uchar tt;
uchar code;
uchar op[4];
};
#define S ((LSym*)0)
#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
MINSIZ = 8,
@ -211,233 +74,55 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
Yi0,
Yi1,
Yi8,
Ys32,
Yi32,
Yi64,
Yiauto,
Yal,
Ycl,
Yax,
Ycx,
Yrb,
Yrl,
Yrf,
Yf0,
Yrx,
Ymb,
Yml,
Ym,
Ybr,
Ycol,
Ycs, Yss, Yds, Yes, Yfs, Ygs,
Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7, Ycr8,
Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7, Yrl32, Yrl64,
Ymr, Ymm,
Yxr, Yxm,
Ymax,
Zxxx = 0,
Zlit,
Zlitm_r,
Z_rp,
Zbr,
Zcall,
Zib_,
Zib_rp,
Zibo_m,
Zibo_m_xm,
Zil_,
Zil_rp,
Ziq_rp,
Zilo_m,
Ziqo_m,
Zjmp,
Zloop,
Zo_iw,
Zm_o,
Zm_r,
Zm2_r,
Zm_r_xm,
Zm_r_i_xm,
Zm_r_3d,
Zm_r_xm_nr,
Zr_m_xm_nr,
Zibm_r, /* mmx1,mmx2/mem64,imm8 */
Zmb_r,
Zaut_r,
Zo_m,
Zo_m64,
Zpseudo,
Zr_m,
Zr_m_xm,
Zr_m_i_xm,
Zrp_,
Z_ib,
Z_il,
Zm_ibo,
Zm_ilo,
Zib_rr,
Zil_rr,
Zclr,
Zbyte,
Zmax,
Px = 0,
P32 = 0x32, /* 32-bit only */
Pe = 0x66, /* operand escape */
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escapes: 66 0f */
Pb = 0xfe, /* byte operands */
Pf2 = 0xf2, /* xmm escape 1: f2 0f */
Pf3 = 0xf3, /* xmm escape 2: f3 0f */
Pq3 = 0x67, /* xmm escape 3: 66 48 0f */
Pw = 0x48, /* Rex.w */
Py = 0x80, /* defaults to 64-bit mode */
Rxf = 1<<9, /* internal flag for Rxr on from */
Rxt = 1<<8, /* internal flag for Rxr on to */
Rxw = 1<<3, /* =1, 64-bit operand size */
Rxr = 1<<2, /* extend modrm reg */
Rxx = 1<<1, /* extend sib index */
Rxb = 1<<0, /* extend modrm r/m, sib base, or opcode reg */
Maxand = 10, /* in -a output width of the byte codes */
};
#pragma varargck type "A" uint
#pragma varargck type "D" Adr*
#pragma varargck type "D" Addr*
#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
#pragma varargck type "i" char*
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
EXTERN int32 INITRND;
EXTERN int64 INITTEXT;
EXTERN int64 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
EXTERN Sym* textp;
EXTERN Sym* etextp;
EXTERN char ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar* rexptr;
EXTERN uchar and[30];
EXTERN int reg[D_NONE];
EXTERN int regrex[D_NONE+1];
EXTERN int32 lcsize;
EXTERN int nerrors;
EXTERN char* noname;
EXTERN char* outfile;
EXTERN vlong pc;
EXTERN char* interpreter;
EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN LSym* symlist;
EXTERN int32 symsize;
EXTERN int tlsoffset;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN char* paramspace;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
EXTERN vlong textstksiz;
EXTERN vlong textarg;
extern Optab optab[];
extern Optab* opindex[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(int32, int);
void addstackmark(void);
Prog* appendp(Prog*);
int Aconv(Fmt *fp);
int Dconv(Fmt *fp);
int Iconv(Fmt *fp);
int Pconv(Fmt *fp);
int Rconv(Fmt *fp);
int Sconv(Fmt *fp);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
void asmsym(void);
void asmelfsym(void);
vlong atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void buildop(void);
Prog* copyp(Prog*);
double cputime(void);
void datblk(int32, int32);
void deadcode(void);
void diag(char*, ...);
void dodata(void);
void doelf(void);
void domacho(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
vlong entryvalue(void);
void follow(void);
void gethunk(void);
void gotypestrings(void);
void diag(char *fmt, ...);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
void listinit(void);
Sym* lookup(char*, int);
void lputb(int32);
void lputl(int32);
void instinit(void);
void main(int, char*[]);
void* mysbrk(uint32);
Prog* newtext(Prog*, Sym*);
void nopout(Prog*);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
void parsetextconst(vlong);
int relinv(int);
vlong rnd(vlong, vlong);
void span(void);
void undef(void);
vlong symaddr(Sym*);
void vputb(uint64);
void vputl(uint64);
void wputb(uint16);
void wputl(uint16);
void xdefine(char*, int, vlong);
void machseg(char*, vlong, vlong, vlong, vlong, uint32, uint32, uint32, uint32);
void machsymseg(uint32, uint32);
void machsect(char*, char*, vlong, vlong, uint32, uint32, uint32, uint32, uint32);
void machstack(vlong);
void machdylink(void);
uint32 machheadr(void);
int machoreloc1(Reloc *r, vlong sectoff);
void main(int argc, char *argv[]);
void parsetextconst(vlong arg);
vlong rnd(vlong v, vlong r);
/* Native is little-endian */
#define LPUT(a) lputl(a)
#define WPUT(a) wputl(a)
#define VPUT(a) vputl(a)
#pragma varargck type "D" Adr*
#pragma varargck type "D" Addr*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "Z" char*

View file

@ -58,21 +58,21 @@ Pconv(Fmt *fp)
case ATEXT:
if(p->from.scale) {
fmtprint(fp, "(%d) %A %D,%d,%lD",
p->line, p->as, &p->from, p->from.scale, &p->to);
p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
fmtprint(fp, "(%d) %A %D,%lD",
p->line, p->as, &p->from, &p->to);
p->lineno, p->as, &p->from, &p->to);
break;
default:
fmtprint(fp, "(%d) %A %D,%D",
p->line, p->as, &p->from, &p->to);
p->lineno, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT_:
case ADYNT_:
fmtprint(fp, "(%d) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
@ -85,17 +85,17 @@ Aconv(Fmt *fp)
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
return fmtstrcpy(fp, anames6[i]);
}
int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
Adr *a;
Addr *a;
int i;
a = va_arg(fp->args, Adr*);
a = va_arg(fp->args, Addr*);
i = a->type;
if(fp->flags & FmtLong) {
@ -182,11 +182,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
snprint(str, sizeof(str), "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
snprint(str, sizeof(str), "$(%.17g)", a->u.dval);
break;
case D_SCONST:
snprint(str, sizeof(str), "$\"%S\"", a->scon);
snprint(str, sizeof(str), "$\"%S\"", a->u.sval);
break;
case D_ADDR:
@ -431,8 +431,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
if(cursym != S) {
tn = cursym->name;
if(ctxt->cursym != S) {
tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);

View file

@ -30,7 +30,6 @@
// Reading object files.
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@ -39,104 +38,12 @@
#include "../ld/pe.h"
#include <ar.h>
char *noname = "<none>";
char* thestring = "amd64";
char* paramspace = "FP";
Header headers[] = {
"plan9x32", Hplan9x32,
"plan9", Hplan9x64,
"elf", Helf,
"darwin", Hdarwin,
"dragonfly", Hdragonfly,
"linux", Hlinux,
"freebsd", Hfreebsd,
"netbsd", Hnetbsd,
"openbsd", Hopenbsd,
"windows", Hwindows,
"windowsgui", Hwindows,
0, 0
};
/*
* -Hplan9x32 -T4128 -R4096 is plan9 32-bit format
* -Hplan9 -T0x200028 -R0x200000 is plan9 64-bit format
* -Helf -T0x80110000 -R4096 is ELF32
* -Hdarwin -Tx -Rx is apple MH-exec
* -Hdragonfly -Tx -Rx is DragonFly elf-exec
* -Hlinux -Tx -Rx is linux elf-exec
* -Hfreebsd -Tx -Rx is FreeBSD elf-exec
* -Hnetbsd -Tx -Rx is NetBSD elf-exec
* -Hopenbsd -Tx -Rx is OpenBSD elf-exec
* -Hwindows -Tx -Rx is MS Windows PE32+
*/
LinkArch* thelinkarch = &linkamd64;
void
main(int argc, char *argv[])
archinit(void)
{
Binit(&bso, 1, OWRITE);
listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = nil;
HEADTYPE = -1;
INITTEXT = -1;
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
linkmode = LinkAuto;
nuxiinit();
flagcount("1", "use alternate profiling code", &debug['1']);
flagcount("8", "assume 64-bit addresses", &debug['8']);
flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
flagint64("D", "addr: data address", &INITDAT);
flagstr("E", "sym: entry symbol", &INITENTRY);
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("O", "print pc-line tables", &debug['O']);
flagcount("Q", "debug byte-register code gen", &debug['Q']);
flagint32("R", "rnd: address rounding", &INITRND);
flagcount("S", "check type signatures", &debug['S']);
flagint64("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);
flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
flagstr("k", "sym: set field tracking symbol", &tracksym);
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();
mywhatsys(); // get goos
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@ -160,30 +67,13 @@ main(int argc, char *argv[])
case Hopenbsd:
break;
}
if(outfile == nil) {
if(HEADTYPE == Hwindows)
outfile = "6.out.exe";
else
outfile = "6.out";
}
libinit();
ctxt->linkmode = linkmode;
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
case Hplan9x32: /* plan 9 */
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+HEADR;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4096;
break;
case Hplan9x64: /* plan 9 */
case Hplan9: /* plan 9 */
HEADR = 32L + 8L;
if(INITTEXT == -1)
INITTEXT = 0x200000+HEADR;
@ -206,7 +96,7 @@ main(int argc, char *argv[])
* OS X system constant - offset from 0(GS) to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_amd64.c.
*/
tlsoffset = 0x8a0;
ctxt->tlsoffset = 0x8a0;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITRND == -1)
@ -227,7 +117,7 @@ main(int argc, char *argv[])
* Also known to ../../pkg/runtime/sys_linux_amd64.s
* and ../../pkg/runtime/cgo/gcc_linux_amd64.c.
*/
tlsoffset = -16;
ctxt->tlsoffset = -16;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@ -251,552 +141,4 @@ main(int argc, char *argv[])
if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%llux is ignored because of -R0x%ux\n",
INITDAT, INITRND);
if(debug['v'])
Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
instinit();
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
zprg.as = AGOK;
zprg.from.type = D_NONE;
zprg.from.index = D_NONE;
zprg.from.scale = 1;
zprg.to = zprg.from;
zprg.mode = 64;
pcstr = "%.6llux ";
histgen = 0;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
addlibpath("command line", "command line", argv[0], "main");
loadlib();
deadcode();
patch();
follow();
doelf();
if(HEADTYPE == Hdarwin)
domacho();
dostkoff();
dostkcheck();
paramspace = "SP"; /* (FP) now (SP) on output */
if(debug['p'])
if(debug['1'])
doprof1();
else
doprof2();
span();
if(HEADTYPE == Hwindows)
dope();
addexport();
textaddress();
pclntab();
symtab();
dodata();
address();
doweak();
reloc();
asmb();
undef();
hostlink();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
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 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void
zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
Sym *s;
Auto *u;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->offset = 0;
if(t & T_OFFSET) {
a->offset = BGETLE4(f);
if(t & T_64) {
a->offset &= 0xFFFFFFFFULL;
a->offset |= (uvlong)BGETLE4(f) << 32;
}
}
a->sym = S;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
a->type = D_NONE;
if(t & T_FCONST) {
a->ieee.l = BGETLE4(f);
a->ieee.h = BGETLE4(f);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->scon, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
if(a->type < 0 || a->type >= D_SIZE)
mangle(pn);
adrgotype = S;
if(t & T_GOTYPE)
adrgotype = zsym(pn, f, h);
s = a->sym;
t = a->type;
if(t == D_INDIR+D_GS || a->index == D_GS)
a->offset += tlsoffset;
if(t != D_AUTO && t != 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 == t) {
if(u->aoffset > l)
u->aoffset = l;
if(adrgotype)
u->gotype = adrgotype;
return;
}
}
switch(t) {
case D_FILE:
case D_FILE1:
case D_AUTO:
case D_PARAM:
if(s == S)
mangle(pn);
}
u = mal(sizeof(*u));
u->link = curauto;
curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
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)
{
vlong ipc;
Prog *p;
int v, o, r, skip, mode;
Sym *h[NSYM], *s;
uint32 sig;
char *name, *x;
int ntext;
vlong eof;
char src[1024];
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;
mode = 64;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
print(" probably not a .6 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(debug['S'] && r == 0)
sig = 1729;
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))
mangle(pn);
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(*p));
p->as = o;
p->line = BGETLE4(f);
p->back = 2;
p->mode = mode;
zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
zaddr(pn, f, &p->to, h);
switch(p->as) {
case ATEXT:
case ADATA:
case AGLOBL:
if(p->from.sym == S)
mangle(pn);
break;
}
if(debug['W'])
print("%P\n", p);
switch(p->as) {
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->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
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);
goto loop;
case AGOK:
diag("%s: GOK opcode in %s", pn, TNAME);
pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
pc++;
goto 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;
}
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;
}
if(cursym != nil && cursym->text) {
histtoauto();
cursym->autom = curauto;
curauto = 0;
}
skip = 0;
if(etextp)
etextp->next = s;
else
textp = s;
etextp = s;
s->text = p;
cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
if(fromgotype) {
if(s->gotype && s->gotype != fromgotype)
diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
s->type = STEXT;
s->hist = gethist();
s->value = pc;
s->args = p->to.offset >> 32;
lastp = p;
p->pc = pc++;
goto loop;
case AMODE:
if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
switch((int)p->from.offset){
case 16: case 32: case 64:
mode = p->from.offset;
break;
}
}
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* 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_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* 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_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
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);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
diag("truncated object file: %s", pn);
}
Prog*
prg(void)
{
Prog *p;
p = mal(sizeof(*p));
*p = zprg;
return p;
}
Prog*
copyp(Prog *q)
{
Prog *p;
p = prg();
*p = *q;
return p;
}
Prog*
appendp(Prog *q)
{
Prog *p;
p = prg();
p->link = q->link;
q->link = p;
p->line = q->line;
p->mode = q->mode;
return p;
}

File diff suppressed because it is too large Load diff

View file

@ -1,991 +0,0 @@
// Inferno utils/6l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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"
#include "../../pkg/runtime/stack.h"
static void xfol(Prog*, Prog**);
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != AJMP)
return p;
p = p->pcond;
}
return P;
}
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 int
nofollow(int a)
{
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case AIRETQ:
case AIRETW:
case ARETFL:
case ARETFQ:
case ARETFW:
case AUNDEF:
return 1;
}
return 0;
}
static int
pushpop(int a)
{
switch(a) {
case APUSHL:
case APUSHFL:
case APUSHQ:
case APUSHFQ:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPQ:
case APOPFQ:
case APOPW:
case APOPFW:
return 1;
}
return 0;
}
static void
xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
enum as a;
loop:
if(p == P)
return;
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
/* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/*
* p goes here, but already used it elsewhere.
* copy up to 4 instructions or else branch to other copy.
*/
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
if(nofollow(a) || pushpop(a))
break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
(*last)->link = q;
*last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
q = prg();
q->as = AJMP;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
/* emit p */
p->mark = 1;
(*last)->link = p;
*last = p;
a = p->as;
/* continue loop with what comes after p */
if(nofollow(a))
return;
if(p->pcond != P && a != ACALL) {
/*
* some kind of conditional branch.
* recurse to follow one path.
* continue loop on the other.
*/
if((q = brchain(p->pcond)) != P)
p->pcond = q;
if((q = brchain(p->link)) != P)
p->link = q;
if(p->from.type == D_CONST) {
if(p->from.offset == 1) {
/*
* expect conditional jump to be taken.
* rewrite so that's the fall-through case.
*/
p->as = relinv(a);
q = p->link;
p->link = p->pcond;
p->pcond = q;
}
} else {
q = p->link;
if(q->mark)
if(a != ALOOP) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
}
xfol(p->link, last);
if(p->pcond->mark)
return;
p = p->pcond;
goto loop;
}
p = p->link;
goto loop;
}
Prog*
byteq(int v)
{
Prog *p;
p = prg();
p->as = ABYTE;
p->from.type = D_CONST;
p->from.offset = v&0xff;
return p;
}
int
relinv(int a)
{
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
errorexit();
return a;
}
void
patch(void)
{
int32 c;
Prog *p, *q;
Sym *s;
int32 vexit;
Sym *gmsym;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
if(flag_shared) {
s = lookup("init_array", 0);
s->type = SINITARR;
s->reachable = 1;
s->hide = 1;
addaddr(s, lookup(INITENTRY, 0));
}
gmsym = lookup("runtime.tlsgm", 0);
if(linkmode != LinkExternal)
gmsym->reachable = 0;
s = lookup("exit", 0);
vexit = s->value;
for(cursym = textp; cursym != nil; cursym = cursym->next)
for(p = cursym->text; p != P; p = p->link) {
if(HEADTYPE == Hwindows) {
// Windows
// Convert
// op n(GS), reg
// to
// MOVL 0x28(GS), reg
// op n(reg), reg
// The purpose of this patch is to fix some accesses
// to extern register variables (TLS) on Windows, as
// a different method is used to access them.
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI
&& p->from.offset <= 8) {
q = appendp(p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVQ;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0x28;
}
}
if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
// ELF uses FS instead of GS.
if(p->from.type == D_INDIR+D_GS)
p->from.type = D_INDIR+D_FS;
if(p->to.type == D_INDIR+D_GS)
p->to.type = D_INDIR+D_FS;
if(p->from.index == D_GS)
p->from.index = D_FS;
if(p->to.index == D_GS)
p->to.index = D_FS;
}
if(!flag_shared) {
// Convert g() or m() accesses of the form
// op n(reg)(GS*1), reg
// to
// op n(GS*1), reg
if(p->from.index == D_FS || p->from.index == D_GS) {
p->from.type = D_INDIR + p->from.index;
p->from.index = D_NONE;
}
// Convert g() or m() accesses of the form
// op reg, n(reg)(GS*1)
// to
// op reg, n(GS*1)
if(p->to.index == D_FS || p->to.index == D_GS) {
p->to.type = D_INDIR + p->to.index;
p->to.index = D_NONE;
}
// Convert get_tls access of the form
// op runtime.tlsgm(SB), reg
// to
// NOP
if(gmsym != S && p->from.sym == gmsym) {
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
p->from.sym = nil;
p->to.sym = nil;
continue;
}
} else {
// Convert TLS reads of the form
// op n(GS), reg
// to
// MOVQ $runtime.tlsgm(SB), reg
// op n(reg)(GS*1), reg
if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(p);
q->to = p->to;
q->as = p->as;
q->from.type = D_INDIR+p->to.type;
q->from.index = p->from.type - D_INDIR;
q->from.scale = 1;
q->from.offset = p->from.offset;
p->as = AMOVQ;
p->from.type = D_EXTERN;
p->from.sym = gmsym;
p->from.offset = 0;
}
}
if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
s = p->to.sym;
if(s) {
if(debug['c'])
Bprint(&bso, "%s calls %s\n", TNAME, s->name);
if((s->type&SMASK) != STEXT) {
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
continue; // avoid more error messages
}
if(s->text == nil)
continue;
p->to.type = D_BRANCH;
p->to.offset = s->text->pc;
p->pcond = 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 in %s (%#ux)\n%P [%s]",
TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
for(cursym = textp; cursym != nil; cursym = cursym->next)
for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}
Prog*
brloop(Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as != AJMP)
break;
c++;
if(c >= 5000)
return P;
}
return q;
}
static char*
morename[] =
{
"runtime.morestack00",
"runtime.morestack10",
"runtime.morestack01",
"runtime.morestack11",
"runtime.morestack8",
"runtime.morestack16",
"runtime.morestack24",
"runtime.morestack32",
"runtime.morestack40",
"runtime.morestack48",
};
Prog* pmorestack[nelem(morename)];
Sym* symmorestack[nelem(morename)];
Sym* gmsym;
static Prog* load_g_cx(Prog*);
static Prog* stacksplit(Prog*, int32, Prog**);
void
dostkoff(void)
{
Prog *p, *q, *q1;
int32 autoffset, deltasp;
int a, pcsize;
uint32 i;
gmsym = lookup("runtime.tlsgm", 0);
for(i=0; i<nelem(morename); i++) {
symmorestack[i] = lookup(morename[i], 0);
if(symmorestack[i]->type != STEXT)
diag("morestack trampoline not defined - %s", morename[i]);
pmorestack[i] = symmorestack[i]->text;
}
for(cursym = textp; cursym != nil; cursym = cursym->next) {
if(cursym->text == nil || cursym->text->link == nil)
continue;
p = cursym->text;
parsetextconst(p->to.offset);
autoffset = textstksiz;
if(autoffset < 0)
autoffset = 0;
if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
for(q = p; q != P; q = q->link)
if(q->as == ACALL)
goto noleaf;
p->from.scale |= NOSPLIT;
noleaf:;
}
if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
diag("nosplit func likely to overflow stack");
q = P;
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
p = appendp(p);
p = load_g_cx(p); // load g into CX
}
if(!(cursym->text->from.scale & NOSPLIT))
p = stacksplit(p, autoffset, &q); // emit split check
if(autoffset) {
p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = autoffset;
p->spadj = autoffset;
} else {
// zero-byte stack adjustment.
// Insert a fake non-zero adjustment so that stkcheck can
// recognize the end of the stack-splitting prolog.
p = appendp(p);
p->as = ANOP;
p->spadj = -PtrSize;
p = appendp(p);
p->as = ANOP;
p->spadj = PtrSize;
}
if(q != P)
q->pcond = p;
deltasp = autoffset;
if(cursym->text->from.scale & WRAPPER) {
// g->panicwrap += autoffset + PtrSize;
p = appendp(p);
p->as = AADDL;
p->from.type = D_CONST;
p->from.offset = autoffset + PtrSize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*PtrSize;
}
if(debug['K'] > 1 && autoffset) {
// 6l -KK means double-check for stack overflow
// even after calling morestack and even if the
// function is marked as nosplit.
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_BX;
p = appendp(p);
p->as = ASUBQ;
p->from.type = D_CONST;
p->from.offset = StackSmall+32;
p->to.type = D_BX;
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_SP;
p->to.type = D_BX;
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
q1 = p;
p = appendp(p);
p->as = AINT;
p->from.type = D_CONST;
p->from.offset = 3;
p = appendp(p);
p->as = ANOP;
q1->pcond = p;
}
if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
// 6l -Z means zero the stack frame on entry.
// This slows down function calls but can help avoid
// false positives in garbage collection.
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_SP;
p->to.type = D_DI;
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_CONST;
p->from.offset = autoffset/8;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_CONST;
p->from.offset = 0;
p->to.type = D_AX;
p = appendp(p);
p->as = AREP;
p = appendp(p);
p->as = ASTOSQ;
}
for(; p != P; p = p->link) {
pcsize = p->mode/8;
a = p->from.type;
if(a == D_AUTO)
p->from.offset += deltasp;
if(a == D_PARAM)
p->from.offset += deltasp + pcsize;
a = p->to.type;
if(a == D_AUTO)
p->to.offset += deltasp;
if(a == D_PARAM)
p->to.offset += deltasp + pcsize;
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
p->spadj = 4;
continue;
case APUSHQ:
case APUSHFQ:
deltasp += 8;
p->spadj = 8;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
p->spadj = 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
p->spadj = -4;
continue;
case APOPQ:
case APOPFQ:
deltasp -= 8;
p->spadj = -8;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
p->spadj = -2;
continue;
case ARET:
break;
}
if(autoffset != deltasp)
diag("unbalanced PUSH/POP");
if(cursym->text->from.scale & WRAPPER) {
p = load_g_cx(p);
p = appendp(p);
// g->panicwrap -= autoffset + PtrSize;
p->as = ASUBL;
p->from.type = D_CONST;
p->from.offset = autoffset + PtrSize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*PtrSize;
p = appendp(p);
p->as = ARET;
}
if(autoffset) {
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = -autoffset;
p->spadj = -autoffset;
p = appendp(p);
p->as = ARET;
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so undo
// the cleanup.
p->spadj = +autoffset;
}
if(p->to.sym) // retjmp
p->as = AJMP;
}
}
}
// Append code to p to load g into cx.
// Overwrites p with the first instruction (no first appendp).
// Overwriting p is unusual but it lets use this in both the
// prologue (caller must call appendp first) and in the epilogue.
// Returns last new instruction.
static Prog*
load_g_cx(Prog *p)
{
if(flag_shared) {
// Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
p->as = AMOVQ;
p->from.type = D_EXTERN;
p->from.sym = gmsym;
p->to.type = D_CX;
p = appendp(p);
}
p->as = AMOVQ;
if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly)
// ELF uses FS
p->from.type = D_INDIR+D_FS;
else
p->from.type = D_INDIR+D_GS;
if(flag_shared) {
// Add TLS offset stored in CX
p->from.index = p->from.type - D_INDIR;
p->from.type = D_INDIR + D_CX;
}
p->from.offset = tlsoffset+0;
p->to.type = D_CX;
if(HEADTYPE == Hwindows) {
// movq %gs:0x28, %rcx
// movq (%rcx), %rcx
p->as = AMOVQ;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0x28;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_CX;
}
return p;
}
// Append code to p to check for stack split.
// Appends to (does not overwrite) p.
// Assumes g is in CX.
// Returns last new instruction.
// On return, *jmpok is the instruction that should jump
// to the stack frame allocation if no split is needed.
static Prog*
stacksplit(Prog *p, int32 framesize, Prog **jmpok)
{
Prog *q, *q1;
uint32 moreconst1, moreconst2, i;
if(debug['K']) {
// 6l -K means check not only for stack
// overflow but stack underflow.
// On underflow, INT 3 (breakpoint).
// Underflow itself is rare but this also
// catches out-of-sync stack guard info
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_INDIR+D_CX;
p->from.offset = 8;
p->to.type = D_SP;
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
p->to.offset = 4;
q1 = p;
p = appendp(p);
p->as = AINT;
p->from.type = D_CONST;
p->from.offset = 3;
p = appendp(p);
p->as = ANOP;
q1->pcond = p;
}
q = P;
q1 = P;
if(framesize <= StackSmall) {
// small stack: SP <= stackguard
// CMPQ SP, stackguard
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_SP;
p->to.type = D_INDIR+D_CX;
} else if(framesize <= StackBig) {
// large stack: SP-framesize <= stackguard-StackSmall
// LEAQ -xxx(SP), AX
// CMPQ AX, stackguard
p = appendp(p);
p->as = ALEAQ;
p->from.type = D_INDIR+D_SP;
p->from.offset = -(framesize-StackSmall);
p->to.type = D_AX;
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_AX;
p->to.type = D_INDIR+D_CX;
} 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.
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// MOVQ stackguard, CX
// CMPQ CX, $StackPreempt
// JEQ label-of-call-to-morestack
// LEAQ StackGuard(SP), AX
// SUBQ CX, AX
// CMPQ AX, $(framesize+(StackGuard-StackSmall))
p = appendp(p);
p->as = AMOVQ;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_SI;
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_SI;
p->to.type = D_CONST;
p->to.offset = StackPreempt;
p = appendp(p);
p->as = AJEQ;
p->to.type = D_BRANCH;
q1 = p;
p = appendp(p);
p->as = ALEAQ;
p->from.type = D_INDIR+D_SP;
p->from.offset = StackGuard;
p->to.type = D_AX;
p = appendp(p);
p->as = ASUBQ;
p->from.type = D_SI;
p->to.type = D_AX;
p = appendp(p);
p->as = ACMPQ;
p->from.type = D_AX;
p->to.type = D_CONST;
p->to.offset = framesize+(StackGuard-StackSmall);
}
// common
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
q = p;
// 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.
moreconst1 = 0;
if(StackTop + textarg + PtrSize + framesize + PtrSize + StackLimit >= StackMin)
moreconst1 = framesize;
moreconst2 = textarg;
if(moreconst2 == 1) // special marker
moreconst2 = 0;
if((moreconst2&7) != 0)
diag("misaligned argument size in stack split");
// 4 varieties varieties (const1==0 cross const2==0)
// and 6 subvarieties of (const1==0 and const2!=0)
p = appendp(p);
if(moreconst1 == 0 && moreconst2 == 0) {
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack[0];
p->to.sym = symmorestack[0];
} else
if(moreconst1 != 0 && moreconst2 == 0) {
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = moreconst1;
p->to.type = D_AX;
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack[1];
p->to.sym = symmorestack[1];
} else
if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
i = moreconst2/8 + 3;
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack[i];
p->to.sym = symmorestack[i];
} else
if(moreconst1 == 0 && moreconst2 != 0) {
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = moreconst2;
p->to.type = D_AX;
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack[2];
p->to.sym = symmorestack[2];
} else {
p->as = AMOVQ;
p->from.type = D_CONST;
p->from.offset = (uint64)moreconst2 << 32;
p->from.offset |= moreconst1;
p->to.type = D_AX;
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack[3];
p->to.sym = symmorestack[3];
}
p = appendp(p);
p->as = AJMP;
p->to.type = D_BRANCH;
p->pcond = cursym->text->link;
if(q != P)
q->pcond = p->link;
if(q1 != P)
q1->pcond = q->link;
*jmpok = q;
return p;
}
vlong
atolwhex(char *s)
{
vlong 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;
}

View file

@ -1,171 +0,0 @@
// Inferno utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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
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(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
q = prg();
q->line = p->line;
q->link = datap;
datap = q;
q->as = ADATA;
q->from.type = D_EXTERN;
q->from.offset = n*4;
q->from.sym = s;
q->from.scale = 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 = AADDL;
p->from.type = D_CONST;
p->from.offset = 1;
p->to.type = D_EXTERN;
p->to.sym = s;
p->to.offset = n*4 + 4;
n += 2;
}
q = prg();
q->line = 0;
q->link = datap;
datap = q;
q->as = ADATA;
q->from.type = D_EXTERN;
q->from.sym = s;
q->from.scale = 4;
q->to.type = D_CONST;
q->to.offset = n;
s->type = SBSS;
s->size = 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(p->from.sym == s2) {
p->from.scale = 1;
ps2 = p;
}
if(p->from.sym == s4) {
p->from.scale = 1;
ps4 = p;
}
}
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
if(p->from.scale & NOPROF) /* dont profile */
continue;
/*
* JMPL profin
*/
q = prg();
q->line = p->line;
q->pc = p->pc;
q->link = p->link;
p->link = q;
p = q;
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = ps2;
p->to.sym = s2;
for(; p; p=p->link) {
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;
/*
* JAL profout
*/
p->as = ACALL;
p->from = zprg.from;
p->to = zprg.to;
p->to.type = D_BRANCH;
p->pcond = ps4;
p->to.sym = s4;
p = q;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -677,15 +677,3 @@ enum
* 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 */
};

View file

@ -43,46 +43,18 @@ char openbsddynld[] = "/usr/libexec/ld.so";
char netbsddynld[] = "/usr/libexec/ld.elf_so";
char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
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;
}
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 %#llx", addr);
return 0;
}
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.
@ -93,11 +65,11 @@ needlib(char *name)
int nelfsym = 1;
static void addpltsym(Sym*);
static void addgotsym(Sym*);
static void addpltsym(Link*, LSym*);
static void addgotsym(Link*, LSym*);
void
adddynrela(Sym *rela, Sym *s, Reloc *r)
adddynrela(LSym *rela, LSym *s, Reloc *r)
{
USED(rela);
USED(s);
@ -106,12 +78,12 @@ adddynrela(Sym *rela, Sym *s, Reloc *r)
}
void
adddynrel(Sym *s, Reloc *r)
adddynrel(LSym *s, Reloc *r)
{
Sym *targ, *rel, *got;
LSym *targ, *rel, *got;
targ = r->sym;
cursym = s;
ctxt->cursym = s;
switch(r->type) {
default:
@ -135,8 +107,8 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_PCREL;
r->add += 4;
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
addpltsym(ctxt, targ);
r->sym = linklookup(ctxt, ".plt", 0);
r->add += targ->plt;
}
return;
@ -153,7 +125,7 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_GOTOFF;
return;
}
addgotsym(targ);
addgotsym(ctxt, targ);
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
r->add += targ->got;
@ -165,7 +137,7 @@ adddynrel(Sym *s, Reloc *r)
case 256 + R_386_GOTPC:
r->type = D_PCREL;
r->sym = lookup(".got", 0);
r->sym = linklookup(ctxt, ".got", 0);
r->add += 4;
return;
@ -183,8 +155,8 @@ adddynrel(Sym *s, Reloc *r)
case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
if(targ->type == SDYNIMPORT) {
addpltsym(targ);
r->sym = lookup(".plt", 0);
addpltsym(ctxt, targ);
r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
r->type = D_PCREL;
return;
@ -204,8 +176,8 @@ adddynrel(Sym *s, Reloc *r)
r->type = D_PCREL;
return;
}
addgotsym(targ);
r->sym = lookup(".got", 0);
addgotsym(ctxt, targ);
r->sym = linklookup(ctxt, ".got", 0);
r->add += targ->got;
r->type = D_PCREL;
return;
@ -217,8 +189,8 @@ adddynrel(Sym *s, Reloc *r)
switch(r->type) {
case D_PCREL:
addpltsym(targ);
r->sym = lookup(".plt", 0);
addpltsym(ctxt, targ);
r->sym = linklookup(ctxt, ".plt", 0);
r->add = targ->plt;
return;
@ -226,10 +198,10 @@ adddynrel(Sym *s, Reloc *r)
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_386_32));
adddynsym(ctxt, targ);
rel = linklookup(ctxt, ".rel", 0);
addaddrplus(ctxt, rel, s, r->off);
adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
r->type = D_CONST; // write r->add during relocsym
r->sym = S;
return;
@ -245,22 +217,22 @@ adddynrel(Sym *s, Reloc *r)
// just in case the C code assigns to the variable,
// and of course it only works for single pointers,
// but we only need to support cgo and that's all it needs.
adddynsym(targ);
got = lookup(".got", 0);
adddynsym(ctxt, targ);
got = linklookup(ctxt, ".got", 0);
s->type = got->type | SSUB;
s->outer = got;
s->sub = got->sub;
got->sub = s;
s->value = got->size;
adduint32(got, 0);
adduint32(lookup(".linkedit.got", 0), targ->dynid);
adduint32(ctxt, got, 0);
adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
r->type = 256; // ignore during relocsym
return;
}
break;
}
cursym = s;
ctxt->cursym = s;
diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
}
@ -304,7 +276,7 @@ int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
Sym *rs;
LSym *rs;
rs = r->xsym;
@ -358,7 +330,7 @@ machoreloc1(Reloc *r, vlong sectoff)
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
archreloc(Reloc *r, LSym *s, vlong *val)
{
USED(s);
if(linkmode == LinkExternal)
@ -368,7 +340,7 @@ archreloc(Reloc *r, Sym *s, vlong *val)
*val = r->add;
return 0;
case D_GOTOFF:
*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
return 0;
}
return -1;
@ -377,119 +349,119 @@ archreloc(Reloc *r, Sym *s, vlong *val)
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) {
// pushl got+4
adduint8(plt, 0xff);
adduint8(plt, 0x35);
addaddrplus(plt, got, 4);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x35);
addaddrplus(ctxt, plt, got, 4);
// jmp *got+8
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addaddrplus(plt, got, 8);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addaddrplus(ctxt, plt, got, 8);
// zero pad
adduint32(plt, 0);
adduint32(ctxt, plt, 0);
// assume got->size == 0 too
addaddrplus(got, lookup(".dynamic", 0), 0);
adduint32(got, 0);
adduint32(got, 0);
addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
adduint32(ctxt, got, 0);
adduint32(ctxt, got, 0);
}
}
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();
// jmpq *got+size
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addaddrplus(plt, got, got->size);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addaddrplus(ctxt, plt, got, got->size);
// add to got: pointer to current pos in plt
addaddrplus(got, plt, plt->size);
addaddrplus(ctxt, got, plt, plt->size);
// pushl $x
adduint8(plt, 0x68);
adduint32(plt, rel->size);
adduint8(ctxt, plt, 0x68);
adduint32(ctxt, plt, rel->size);
// jmp .plt
adduint8(plt, 0xe9);
adduint32(plt, -(plt->size+4));
adduint8(ctxt, plt, 0xe9);
adduint32(ctxt, plt, -(plt->size+4));
// rel
addaddrplus(rel, got, got->size-4);
adduint32(rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
addaddrplus(ctxt, rel, got, got->size-4);
adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
s->plt = plt->size - 16;
} else if(HEADTYPE == Hdarwin) {
// Same laziness as in 6l.
Sym *plt;
LSym *plt;
plt = lookup(".plt", 0);
plt = linklookup(ctxt, ".plt", 0);
addgotsym(s);
addgotsym(ctxt, s);
adduint32(lookup(".linkedit.plt", 0), s->dynid);
adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
// jmpq *got+size(IP)
s->plt = plt->size;
adduint8(plt, 0xff);
adduint8(plt, 0x25);
addaddrplus(plt, lookup(".got", 0), s->got);
adduint8(ctxt, plt, 0xff);
adduint8(ctxt, plt, 0x25);
addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
} else {
diag("addpltsym: unsupported binary format");
}
}
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_386_GLOB_DAT));
rel = linklookup(ctxt, ".rel", 0);
addaddrplus(ctxt, rel, got, s->got);
adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
} else if(HEADTYPE == Hdarwin) {
adduint32(lookup(".linkedit.got", 0), s->dynid);
adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
} else {
diag("addgotsym: unsupported binary format");
}
}
void
adddynsym(Sym *s)
adddynsym(Link *ctxt, LSym *s)
{
Sym *d;
LSym *d;
int t;
char *name;
@ -499,20 +471,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;
@ -520,12 +492,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:
@ -542,7 +514,7 @@ adddynsym(Sym *s)
t = 14;
break;
}
adduint16(d, t);
adduint16(ctxt, d, t);
}
} else if(HEADTYPE == Hdarwin) {
diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
@ -556,16 +528,16 @@ 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 if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else if(HEADTYPE != Hwindows) {
@ -576,10 +548,10 @@ adddynlib(char *lib)
void
asmb(void)
{
int32 v, magic;
int32 magic;
uint32 symo, dwarfoff, machlink;
Section *sect;
Sym *sym;
LSym *sym;
int i;
if(debug['v'])
@ -641,18 +613,7 @@ asmb(void)
default:
if(iself)
goto Elfsym;
case Hgarbunix:
symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
break;
case Hunixcoff:
symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
break;
case Hplan9x32:
symo = HEADR+segtext.filelen+segdata.filelen;
break;
case Hmsdoscom:
case Hmsdosexe:
debug['s'] = 1;
case Hplan9:
symo = HEADR+segtext.filelen+segdata.filelen;
break;
case Hdarwin:
@ -685,11 +646,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++)
@ -715,96 +676,7 @@ asmb(void)
cseek(0L);
switch(HEADTYPE) {
default:
case Hgarbunix: /* garbage */
lputb(0x160L<<16); /* magic and sections */
lputb(0L); /* time and date */
lputb(rnd(HEADR+segtext.filelen, 4096)+segdata.filelen);
lputb(symsize); /* nsyms */
lputb((0x38L<<16)|7L); /* size of optional hdr and flags */
lputb((0413<<16)|0437L); /* magic and version */
lputb(rnd(HEADR+segtext.filelen, 4096)); /* sizes */
lputb(segdata.filelen);
lputb(segdata.len - segdata.filelen);
lputb(entryvalue()); /* va of entry */
lputb(INITTEXT-HEADR); /* va of base of text */
lputb(segdata.vaddr); /* va of base of data */
lputb(segdata.vaddr+segdata.filelen); /* va of base of bss */
lputb(~0L); /* gp reg mask */
lputb(0L);
lputb(0L);
lputb(0L);
lputb(0L);
lputb(~0L); /* gp value ?? */
break;
case Hunixcoff: /* unix coff */
/*
* file header
*/
lputl(0x0004014c); /* 4 sections, magic */
lputl(0); /* unix time stamp */
lputl(0); /* symbol table */
lputl(0); /* nsyms */
lputl(0x0003001c); /* flags, sizeof a.out header */
/*
* a.out header
*/
lputl(0x10b); /* magic, version stamp */
lputl(rnd(segtext.filelen, INITRND)); /* text sizes */
lputl(segdata.filelen); /* data sizes */
lputl(segdata.len - segdata.filelen); /* bss sizes */
lputb(entryvalue()); /* va of entry */
lputl(INITTEXT); /* text start */
lputl(segdata.vaddr); /* data start */
/*
* text section header
*/
s8put(".text");
lputl(HEADR); /* pa */
lputl(HEADR); /* va */
lputl(segtext.filelen); /* text size */
lputl(HEADR); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x20); /* flags text only */
/*
* data section header
*/
s8put(".data");
lputl(segdata.vaddr); /* pa */
lputl(segdata.vaddr); /* va */
lputl(segdata.filelen); /* data size */
lputl(HEADR+segtext.filelen); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x40); /* flags data only */
/*
* bss section header
*/
s8put(".bss");
lputl(segdata.vaddr+segdata.filelen); /* pa */
lputl(segdata.vaddr+segdata.filelen); /* va */
lputl(segdata.len - segdata.filelen); /* bss size */
lputl(0); /* file offset */
lputl(0); /* relocation */
lputl(0); /* line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x80); /* flags bss only */
/*
* comment section header
*/
s8put(".comment");
lputl(0); /* pa */
lputl(0); /* va */
lputl(symsize+lcsize); /* comment size */
lputl(HEADR+segtext.filelen+segdata.filelen); /* file offset */
lputl(HEADR+segtext.filelen+segdata.filelen); /* offset of syms */
lputl(HEADR+segtext.filelen+segdata.filelen+symsize);/* offset of line numbers */
lputl(0); /* relocation, line numbers */
lputl(0x200); /* flags comment only */
break;
case Hplan9x32: /* plan9 */
case Hplan9: /* plan9 */
magic = 4*11*11+7;
lputb(magic); /* magic */
lputb(segtext.filelen); /* sizes */
@ -815,31 +687,6 @@ asmb(void)
lputb(spsize); /* sp offsets */
lputb(lcsize); /* line offsets */
break;
case Hmsdoscom:
/* MS-DOS .COM */
break;
case Hmsdosexe:
/* fake MS-DOS .EXE */
v = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
wputl(0x5A4D); /* 'MZ' */
wputl(v % 512); /* bytes in last page */
wputl(rnd(v, 512)/512); /* total number of pages */
wputl(0x0000); /* number of reloc items */
v = rnd(HEADR-(INITTEXT & 0xFFFF), 16);
wputl(v/16); /* size of header */
wputl(0x0000); /* minimum allocation */
wputl(0xFFFF); /* maximum allocation */
wputl(0x0000); /* initial ss value */
wputl(0x0100); /* initial sp value */
wputl(0x0000); /* complemented checksum */
v = entryvalue();
wputl(v); /* initial ip value (!) */
wputl(0x0000); /* initial cs value */
wputl(0x0000);
wputl(0x0000);
wputl(0x003E); /* reloc table offset */
wputl(0x0000); /* overlay number */
break;
case Hdarwin:
asmbmacho();
break;

View file

@ -31,6 +31,7 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "8.out.h"
#ifndef EXTERN
@ -47,136 +48,8 @@ enum
};
#define P ((Prog*)0)
#define S ((Sym*)0)
#define TNAME (cursym?cursym->name:noname)
typedef struct Adr Adr;
typedef struct Prog Prog;
typedef struct Sym Sym;
typedef struct Auto Auto;
typedef struct Optab Optab;
typedef struct Reloc Reloc;
struct Adr
{
union
{
int32 u0offset;
char u0scon[8];
Prog *u0cond; /* not used, but should be D_BRANCH */
Ieee u0ieee;
char *u0sbig;
} u0;
Sym* sym;
short type;
uchar index;
char scale;
int32 offset2;
};
#define offset u0.u0offset
#define scon u0.u0scon
#define cond u0.u0cond
#define ieee u0.u0ieee
#define sbig u0.u0sbig
struct Reloc
{
int32 off;
uchar siz;
uchar done;
int32 type;
int32 add;
int32 xadd;
Sym* sym;
Sym* xsym;
};
struct Prog
{
Adr from;
Adr to;
Prog* forwd;
Prog* comefrom;
Prog* link;
Prog* pcond; /* work on this */
int32 pc;
int32 spadj;
int32 line;
short as;
char width; /* fake for DATA */
char ft; /* oclass cache */
char tt;
uchar mark; /* work on these */
uchar back;
uchar bigjmp;
};
#define datasize from.scale
#define textflag from.scale
#define iscall(p) ((p)->as == ACALL)
struct Auto
{
Sym* asym;
Auto* link;
int32 aoffset;
short type;
Sym* gotype;
};
struct Sym
{
char* name;
char* extname; // name used in external object files
short type;
short version;
uchar dupok;
uchar reachable;
uchar cgoexport;
uchar special;
uchar stkcheck;
uchar hide;
int32 value;
int32 size;
int32 sig;
int32 dynid;
int32 plt;
int32 got;
int32 align; // if non-zero, required alignment in bytes
int32 elfsym;
int32 args; // size of stack frame incoming arguments area
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
Sym* next; // in text or data list
Sym* sub; // in sub list
Sym* outer; // container of sub
Sym* gotype;
Sym* reachparent;
Sym* queue;
char* file;
char* dynimplib;
char* dynimpvers;
struct Section* sect;
struct Hist* hist; // for ATEXT
// STEXT
Auto* autom;
Prog* text;
// SDATA, SBSS
uchar* p;
int32 np;
int32 maxp;
Reloc* r;
int32 nr;
int32 maxr;
};
struct Optab
{
short as;
uchar* ytab;
uchar prefix;
uchar op[13];
};
#define S ((LSym*)0)
#define TNAME (ctxt->cursym?ctxt->cursym->name:noname)
enum
{
@ -185,202 +58,50 @@ enum
MINLC = 1,
MAXIO = 8192,
MAXHIST = 40, /* limit of path elements for history symbols */
Yxxx = 0,
Ynone,
Yi0,
Yi1,
Yi8,
Yi32,
Yiauto,
Yal,
Ycl,
Yax,
Ycx,
Yrb,
Yrl,
Yrf,
Yf0,
Yrx,
Ymb,
Yml,
Ym,
Ybr,
Ycol,
Ycs, Yss, Yds, Yes, Yfs, Ygs,
Ygdtr, Yidtr, Yldtr, Ymsw, Ytask,
Ycr0, Ycr1, Ycr2, Ycr3, Ycr4, Ycr5, Ycr6, Ycr7,
Ydr0, Ydr1, Ydr2, Ydr3, Ydr4, Ydr5, Ydr6, Ydr7,
Ytr0, Ytr1, Ytr2, Ytr3, Ytr4, Ytr5, Ytr6, Ytr7,
Ymr, Ymm,
Yxr, Yxm,
Ymax,
Zxxx = 0,
Zlit,
Zlitm_r,
Z_rp,
Zbr,
Zcall,
Zcallcon,
Zcallind,
Zib_,
Zib_rp,
Zibo_m,
Zil_,
Zil_rp,
Zilo_m,
Zjmp,
Zjmpcon,
Zloop,
Zm_o,
Zm_r,
Zm2_r,
Zm_r_xm,
Zm_r_i_xm,
Zaut_r,
Zo_m,
Zpseudo,
Zr_m,
Zr_m_xm,
Zr_m_i_xm,
Zrp_,
Z_ib,
Z_il,
Zm_ibo,
Zm_ilo,
Zib_rr,
Zil_rr,
Zclr,
Zibm_r, /* mmx1,mmx2/mem64,imm8 */
Zbyte,
Zmov,
Zmax,
Px = 0,
Pe = 0x66, /* operand escape */
Pm = 0x0f, /* 2byte opcode escape */
Pq = 0xff, /* both escape */
Pb = 0xfe, /* byte operands */
Pf2 = 0xf2, /* xmm escape 1 */
Pf3 = 0xf3, /* xmm escape 2 */
};
#pragma varargck type "A" int
#pragma varargck type "D" Adr*
#pragma varargck type "D" Addr*
#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
#pragma varargck type "Y" Sym*
#pragma varargck type "Y" LSym*
#pragma varargck type "Z" char*
#pragma varargck type "i" char*
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
EXTERN int32 INITRND;
EXTERN int32 INITTEXT;
EXTERN int32 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN char* pcstr;
EXTERN Auto* curauto;
EXTERN Auto* curhist;
EXTERN Prog* curp;
EXTERN Sym* cursym;
EXTERN Sym* datap;
EXTERN LSym* datap;
EXTERN int debug[128];
EXTERN char literal[32];
EXTERN Sym* etextp;
EXTERN Prog* firstp;
EXTERN uchar ycover[Ymax*Ymax];
EXTERN uchar* andptr;
EXTERN uchar and[100];
EXTERN char reg[D_NONE];
EXTERN int32 lcsize;
EXTERN int maxop;
EXTERN int nerrors;
EXTERN char* noname;
EXTERN int32 pc;
EXTERN char* rpath;
EXTERN int32 spsize;
EXTERN Sym* symlist;
EXTERN LSym* symlist;
EXTERN int32 symsize;
EXTERN Sym* textp;
EXTERN int32 textsize;
EXTERN Prog zprg;
EXTERN int dtype;
EXTERN int tlsoffset;
EXTERN Sym* adrgotype; // type symbol on last Adr read
EXTERN Sym* fromgotype; // type symbol on last p->from read
extern Optab optab[];
extern char* anames[];
int Aconv(Fmt*);
int Dconv(Fmt*);
int Iconv(Fmt*);
int Pconv(Fmt*);
int Rconv(Fmt*);
int Sconv(Fmt*);
void addhist(int32, int);
Prog* appendp(Prog*);
int Aconv(Fmt *fp);
int Dconv(Fmt *fp);
int Iconv(Fmt *fp);
int Pconv(Fmt *fp);
int Rconv(Fmt *fp);
int Sconv(Fmt *fp);
void adddynlib(char *lib);
void adddynrel(LSym *s, Reloc *r);
void adddynrela(LSym *rela, LSym *s, Reloc *r);
void adddynsym(Link *ctxt, LSym *s);
int archreloc(Reloc *r, LSym *s, vlong *val);
void asmb(void);
void asmdyn(void);
void asmins(Prog*);
void asmsym(void);
int32 atolwhex(char*);
Prog* brchain(Prog*);
Prog* brloop(Prog*);
void cflush(void);
Prog* copyp(Prog*);
vlong cpos(void);
double cputime(void);
void diag(char*, ...);
void dodata(void);
void doelf(void);
void doprof1(void);
void doprof2(void);
void dostkoff(void);
int32 entryvalue(void);
void follow(void);
void instinit(void);
void diag(char *fmt, ...);
int elfreloc1(Reloc *r, vlong sectoff);
void elfsetupplt(void);
void listinit(void);
Sym* lookup(char*, int);
void lputb(int32);
void lputl(int32);
void vputl(uint64);
void strnput(char*, int);
void main(int, char*[]);
void* mal(uint32);
int opsize(Prog*);
void patch(void);
Prog* prg(void);
int relinv(int);
int32 rnd(int32, int32);
void s8put(char*);
void span(void);
void undef(void);
int32 symaddr(Sym*);
void wput(ushort);
void wputl(ushort);
void xdefine(char*, int, int32);
uint32 machheadr(void);
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);
/*
* go.c
*/
void deadcode(void);
int machoreloc1(Reloc *r, vlong sectoff);
void main(int argc, char *argv[]);
int32 rnd(int32 v, int32 r);
void s8put(char *n);
char* xsymname(LSym *s);
/* Native is little-endian */
#define LPUT(a) lputl(a)

View file

@ -58,18 +58,18 @@ Pconv(Fmt *fp)
case ATEXT:
if(p->from.scale) {
fmtprint(fp, "(%d) %A %D,%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
default:
fmtprint(fp, "(%d) %A %D,%D",
p->line, p->as, &p->from, &p->to);
p->lineno, p->as, &p->from, &p->to);
break;
case ADATA:
case AINIT_:
case ADYNT_:
fmtprint(fp, "(%d) %A %D/%d,%D",
p->line, p->as, &p->from, p->from.scale, &p->to);
p->lineno, p->as, &p->from, p->from.scale, &p->to);
break;
}
bigP = P;
@ -82,11 +82,11 @@ Aconv(Fmt *fp)
int i;
i = va_arg(fp->args, int);
return fmtstrcpy(fp, anames[i]);
return fmtstrcpy(fp, anames8[i]);
}
char*
xsymname(Sym *s)
xsymname(LSym *s)
{
if(s == nil)
return "!!noname!!";
@ -97,10 +97,10 @@ int
Dconv(Fmt *fp)
{
char str[STRINGSZ], s[STRINGSZ];
Adr *a;
Addr *a;
int i;
a = va_arg(fp->args, Adr*);
a = va_arg(fp->args, Addr*);
i = a->type;
if(i >= D_INDIR && i < 2*D_INDIR) {
if(a->offset)
@ -159,11 +159,11 @@ Dconv(Fmt *fp)
break;
case D_FCONST:
snprint(str, sizeof str, "$(%.8ux,%.8ux)", a->ieee.h, a->ieee.l);
snprint(str, sizeof str, "$(%.17g)", a->u.dval);
break;
case D_SCONST:
snprint(str, sizeof str, "$\"%S\"", a->scon);
snprint(str, sizeof str, "$\"%S\"", a->u.sval);
break;
case D_ADDR:
@ -361,8 +361,8 @@ diag(char *fmt, ...)
tn = "";
sep = "";
if(cursym != S) {
tn = cursym->name;
if(ctxt->cursym != S) {
tn = ctxt->cursym->name;
sep = ": ";
}
va_start(arg, fmt);

View file

@ -30,7 +30,6 @@
// Reading object files.
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
@ -39,110 +38,12 @@
#include "../ld/pe.h"
#include <ar.h>
#ifndef DEFAULT
#define DEFAULT '9'
#endif
char *noname = "<none>";
char *thestring = "386";
Header headers[] = {
"garbunix", Hgarbunix,
"unixcoff", Hunixcoff,
"plan9", Hplan9x32,
"msdoscom", Hmsdoscom,
"msdosexe", Hmsdosexe,
"darwin", Hdarwin,
"dragonfly", Hdragonfly,
"linux", Hlinux,
"freebsd", Hfreebsd,
"netbsd", Hnetbsd,
"openbsd", Hopenbsd,
"windows", Hwindows,
"windowsgui", Hwindows,
0, 0
};
/*
* -Hgarbunix -T0x40004C -D0x10000000 is garbage unix
* -Hunixcoff -T0xd0 -R4 is unix coff
* -Hplan9 -T4128 -R4096 is plan9 format
* -Hmsdoscom -Tx -Rx is MS-DOS .COM
* -Hmsdosexe -Tx -Rx is fake MS-DOS .EXE
* -Hdarwin -Tx -Rx is Apple Mach-O
* -Hdragonfly -Tx -Rx is DragonFly ELF32
* -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
*/
char* thestring = "386";
LinkArch* thelinkarch = &link386;
void
main(int argc, char *argv[])
archinit(void)
{
Binit(&bso, 1, OWRITE);
listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = nil;
HEADTYPE = -1;
INITTEXT = -1;
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
linkmode = LinkAuto;
nuxiinit();
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);
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("O", "print pc-line tables", &debug['O']);
flagcount("Q", "debug byte-register code gen", &debug['Q']);
flagint32("R", "rnd: address rounding", &INITRND);
flagcount("S", "check type signatures", &debug['S']);
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);
flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
flagstr("k", "sym: set field tracking symbol", &tracksym);
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("n", "dump symbol table", &debug['n']);
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']);
// TODO: link mode flag
flagparse(&argc, &argv, usage);
if(argc != 1)
usage();
mywhatsys(); // get goos
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
@ -163,41 +64,15 @@ main(int argc, char *argv[])
case Hopenbsd:
break;
}
if(outfile == nil) {
if(HEADTYPE == Hwindows)
outfile = "8.out.exe";
else
outfile = "8.out";
}
libinit();
ctxt->linkmode = linkmode;
switch(HEADTYPE) {
default:
diag("unknown -H option");
errorexit();
case Hgarbunix: /* this is garbage */
HEADR = 20L+56L;
if(INITTEXT == -1)
INITTEXT = 0x40004CL;
if(INITDAT == -1)
INITDAT = 0x10000000L;
if(INITRND == -1)
INITRND = 0;
break;
case Hunixcoff: /* is unix coff */
HEADR = 0xd0L;
if(INITTEXT == -1)
INITTEXT = 0xd0;
if(INITDAT == -1)
INITDAT = 0x400000;
if(INITRND == -1)
INITRND = 0;
break;
case Hplan9x32: /* plan 9 */
tlsoffset = -8;
case Hplan9: /* plan 9 */
ctxt->tlsoffset = -8;
HEADR = 32L;
if(INITTEXT == -1)
INITTEXT = 4096+32;
@ -206,33 +81,12 @@ main(int argc, char *argv[])
if(INITRND == -1)
INITRND = 4096;
break;
case Hmsdoscom: /* MS-DOS .COM */
HEADR = 0;
if(INITTEXT == -1)
INITTEXT = 0x0100;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4;
break;
case Hmsdosexe: /* fake MS-DOS .EXE */
HEADR = 0x200;
if(INITTEXT == -1)
INITTEXT = 0x0100;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
INITRND = 4;
HEADR += (INITTEXT & 0xFFFF);
if(debug['v'])
Bprint(&bso, "HEADR = 0x%d\n", HEADR);
break;
case Hdarwin: /* apple MACH */
/*
* OS X system constant - offset from %gs to our TLS.
* Explained in ../../pkg/runtime/cgo/gcc_darwin_386.c.
*/
tlsoffset = 0x468;
ctxt->tlsoffset = 0x468;
machoinit();
HEADR = INITIAL_MACHO_HEADR;
if(INITTEXT == -1)
@ -253,7 +107,7 @@ main(int argc, char *argv[])
* Also known to ../../pkg/runtime/sys_linux_386.s
* and ../../pkg/runtime/cgo/gcc_linux_386.c.
*/
tlsoffset = -8;
ctxt->tlsoffset = -8;
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
@ -277,516 +131,4 @@ 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);
instinit();
zprg.link = P;
zprg.pcond = P;
zprg.back = 2;
zprg.as = AGOK;
zprg.from.type = D_NONE;
zprg.from.index = D_NONE;
zprg.from.scale = 1;
zprg.to = zprg.from;
pcstr = "%.6ux ";
histgen = 0;
pc = 0;
dtype = 4;
version = 0;
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
addlibpath("command line", "command line", argv[0], "main");
loadlib();
deadcode();
patch();
follow();
doelf();
if(HEADTYPE == Hdarwin)
domacho();
if(HEADTYPE == Hwindows)
dope();
dostkoff();
dostkcheck();
if(debug['p'])
if(debug['1'])
doprof1();
else
doprof2();
span();
addexport();
textaddress();
pclntab();
symtab();
dodata();
address();
doweak();
reloc();
asmb();
undef();
hostlink();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", nsymbol);
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 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void
zaddr(char *pn, Biobuf *f, Adr *a, Sym *h[])
{
int t;
int32 l;
Sym *s;
Auto *u;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->type = D_NONE;
a->offset = 0;
if(t & T_OFFSET)
a->offset = BGETLE4(f);
a->offset2 = 0;
if(t & T_OFFSET2) {
a->offset2 = BGETLE4(f);
a->type = D_CONST2;
}
a->sym = S;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
a->ieee.l = BGETLE4(f);
a->ieee.h = BGETLE4(f);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->scon, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
adrgotype = S;
if(t & T_GOTYPE)
adrgotype = zsym(pn, f, h);
t = a->type;
if(t == D_INDIR+D_GS)
a->offset += tlsoffset;
s = a->sym;
if(s == S)
return;
if(t != D_AUTO && t != D_PARAM) {
if(adrgotype)
s->gotype = adrgotype;
return;
}
l = a->offset;
for(u=curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
if(adrgotype)
u->gotype = adrgotype;
return;
}
}
u = mal(sizeof(*u));
u->link = curauto;
curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
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;
int v, o, r, skip;
Sym *h[NSYM], *s;
uint32 sig;
int ntext;
int32 eof;
char *name, *x;
char src[1024];
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;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
print(" probably not a .%c file\n", thechar);
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(debug['S'] && r == 0)
sig = 1729;
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))
mangle(pn);
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(*p));
p->as = o;
p->line = BGETLE4(f);
p->back = 2;
zaddr(pn, f, &p->from, h);
fromgotype = adrgotype;
zaddr(pn, f, &p->to, h);
if(debug['W'])
print("%P\n", p);
switch(p->as) {
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->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
diag("%s: redefinition: %s in %s",
pn, s->name, TNAME);
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
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);
goto loop;
case AGOK:
diag("%s: GOK opcode in %s", pn, TNAME);
pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
pc++;
goto 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;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(debug['v'])
diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
if(cursym != nil && cursym->text) {
histtoauto();
cursym->autom = curauto;
curauto = 0;
}
skip = 0;
if(etextp)
etextp->next = s;
else
textp = s;
etextp = s;
s->text = p;
cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
s->type = STEXT;
s->hist = gethist();
s->value = pc;
s->args = p->to.offset2;
lastp = p;
p->pc = pc++;
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* 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_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* 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_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
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);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
diag("truncated object file: %s", pn);
}
Prog*
prg(void)
{
Prog *p;
p = mal(sizeof(Prog));
*p = zprg;
return p;
}
Prog*
copyp(Prog *q)
{
Prog *p;
p = prg();
*p = *q;
return p;
}
Prog*
appendp(Prog *q)
{
Prog *p;
p = prg();
p->link = q->link;
q->link = p;
p->line = q->line;
return p;
}

File diff suppressed because it is too large Load diff

View file

@ -1,858 +0,0 @@
// Inferno utils/8l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/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"
#include "../../pkg/runtime/stack.h"
static void xfol(Prog*, Prog**);
Prog*
brchain(Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == P || p->as != AJMP)
return p;
p = p->pcond;
}
return P;
}
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 int
nofollow(int a)
{
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case AIRETW:
case AUNDEF:
return 1;
}
return 0;
}
static int
pushpop(int a)
{
switch(a) {
case APUSHL:
case APUSHFL:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPW:
case APOPFW:
return 1;
}
return 0;
}
static void
xfol(Prog *p, Prog **last)
{
Prog *q;
int i;
enum as a;
loop:
if(p == P)
return;
if(p->as == AJMP)
if((q = p->pcond) != P && q->as != ATEXT) {
/* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/*
* p goes here, but already used it elsewhere.
* copy up to 4 instructions or else branch to other copy.
*/
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == P)
break;
if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
if(nofollow(a) || pushpop(a))
break; // NOTE(rsc): arm does goto copy
if(q->pcond == P || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(p);
p = p->link;
q->mark = 1;
(*last)->link = q;
*last = q;
if(q->as != a || q->pcond == P || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
q = prg();
q->as = AJMP;
q->line = p->line;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
/* emit p */
p->mark = 1;
(*last)->link = p;
*last = p;
a = p->as;
/* continue loop with what comes after p */
if(nofollow(a))
return;
if(p->pcond != P && a != ACALL) {
/*
* some kind of conditional branch.
* recurse to follow one path.
* continue loop on the other.
*/
if((q = brchain(p->pcond)) != P)
p->pcond = q;
if((q = brchain(p->link)) != P)
p->link = q;
if(p->from.type == D_CONST) {
if(p->from.offset == 1) {
/*
* expect conditional jump to be taken.
* rewrite so that's the fall-through case.
*/
p->as = relinv(a);
q = p->link;
p->link = p->pcond;
p->pcond = q;
}
} else {
q = p->link;
if(q->mark)
if(a != ALOOP) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
}
xfol(p->link, last);
if(p->pcond->mark)
return;
p = p->pcond;
goto loop;
}
p = p->link;
goto loop;
}
int
relinv(int a)
{
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
diag("unknown relation: %s in %s", anames[a], TNAME);
return a;
}
void
patch(void)
{
int32 c;
Prog *p, *q;
Sym *s;
int32 vexit;
Sym *plan9_tos;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
mkfwd();
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
s = lookup("exit", 0);
vexit = s->value;
plan9_tos = S;
if(HEADTYPE == Hplan9x32)
plan9_tos = lookup("_tos", 0);
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
if(HEADTYPE == Hwindows) {
// Convert
// op n(GS), reg
// to
// 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
// a different method is used to access them.
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x14;
}
}
if(HEADTYPE == Hlinux) {
// Running binaries under Xen requires using
// MOVL 0(GS), reg
// and then off(reg) instead of saying off(GS) directly
// when the offset is negative.
// In external mode we just produce a reloc.
if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
&& p->to.type >= D_AX && p->to.type <= D_DI) {
if(linkmode != LinkExternal) {
q = appendp(p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0;
} else {
// Add signals to relocate.
p->from.index = D_GS;
p->from.scale = 1;
}
}
}
if(HEADTYPE == Hplan9x32) {
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_EXTERN;
p->from.sym = plan9_tos;
p->from.offset = 0;
}
}
if((p->as == ACALL && p->to.type != D_BRANCH) || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
s = p->to.sym;
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&SMASK) != STEXT) {
/* diag prints TNAME first */
diag("undefined: %s", s->name);
s->type = STEXT;
s->value = vexit;
continue; // avoid more error messages
}
if(s->text == nil)
continue;
p->to.type = D_BRANCH;
p->to.offset = s->text->pc;
p->pcond = 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 in %s (%#ux)\n%P [%s]",
TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = D_NONE;
}
p->pcond = q;
}
}
for(cursym = textp; cursym != nil; cursym = cursym->next) {
if(cursym->text == nil || cursym->p != nil)
continue;
for(p = cursym->text; p != P; p = p->link) {
p->mark = 0; /* initialization for follow */
if(p->pcond != P) {
p->pcond = brloop(p->pcond);
if(p->pcond != P)
if(p->to.type == D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}
}
Prog*
brloop(Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != P; q = q->pcond) {
if(q->as != AJMP)
break;
c++;
if(c >= 5000)
return P;
}
return q;
}
static Prog* load_g_cx(Prog*);
static Prog* stacksplit(Prog*, int32, Prog**);
static Sym *plan9_tos;
static Prog *pmorestack;
static Sym *symmorestack;
void
dostkoff(void)
{
Prog *p, *q;
int32 autoffset, deltasp;
int a;
pmorestack = P;
symmorestack = lookup("runtime.morestack", 0);
if(symmorestack->type != STEXT)
diag("runtime.morestack not defined");
else {
pmorestack = symmorestack->text;
symmorestack->text->from.scale |= NOSPLIT;
}
plan9_tos = S;
if(HEADTYPE == Hplan9x32)
plan9_tos = lookup("_tos", 0);
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;
q = P;
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
p = appendp(p);
p = load_g_cx(p); // load g into CX
}
if(!(cursym->text->from.scale & NOSPLIT))
p = stacksplit(p, autoffset, &q); // emit split check
if(autoffset) {
p = appendp(p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = autoffset;
p->spadj = autoffset;
} else {
// zero-byte stack adjustment.
// Insert a fake non-zero adjustment so that stkcheck can
// recognize the end of the stack-splitting prolog.
p = appendp(p);
p->as = ANOP;
p->spadj = -PtrSize;
p = appendp(p);
p->as = ANOP;
p->spadj = PtrSize;
}
if(q != P)
q->pcond = p;
deltasp = autoffset;
if(cursym->text->from.scale & WRAPPER) {
// g->panicwrap += autoffset + PtrSize;
p = appendp(p);
p->as = AADDL;
p->from.type = D_CONST;
p->from.offset = autoffset + PtrSize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*PtrSize;
}
if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
// 8l -Z means zero the stack frame on entry.
// This slows down function calls but can help avoid
// false positives in garbage collection.
p = appendp(p);
p->as = AMOVL;
p->from.type = D_SP;
p->to.type = D_DI;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = autoffset/4;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = 0;
p->to.type = D_AX;
p = appendp(p);
p->as = AREP;
p = appendp(p);
p->as = ASTOSL;
}
for(; p != P; p = p->link) {
a = p->from.type;
if(a == D_AUTO)
p->from.offset += deltasp;
if(a == D_PARAM)
p->from.offset += deltasp + 4;
a = p->to.type;
if(a == D_AUTO)
p->to.offset += deltasp;
if(a == D_PARAM)
p->to.offset += deltasp + 4;
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
p->spadj = 4;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
p->spadj = 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
p->spadj = -4;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
p->spadj = -2;
continue;
case ARET:
break;
}
if(autoffset != deltasp)
diag("unbalanced PUSH/POP");
if(cursym->text->from.scale & WRAPPER) {
p = load_g_cx(p);
p = appendp(p);
// g->panicwrap -= autoffset + PtrSize;
p->as = ASUBL;
p->from.type = D_CONST;
p->from.offset = autoffset + PtrSize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*PtrSize;
p = appendp(p);
p->as = ARET;
}
if(autoffset) {
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = -autoffset;
p->spadj = -autoffset;
p = appendp(p);
p->as = ARET;
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so undo
// the cleanup.
p->spadj = +autoffset;
}
if(p->to.sym) // retjmp
p->as = AJMP;
}
}
}
// Append code to p to load g into cx.
// Overwrites p with the first instruction (no first appendp).
// Overwriting p is unusual but it lets use this in both the
// prologue (caller must call appendp first) and in the epilogue.
// Returns last new instruction.
static Prog*
load_g_cx(Prog *p)
{
switch(HEADTYPE) {
case Hwindows:
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x14;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_CX;
break;
case Hlinux:
if(linkmode != LinkExternal) {
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = tlsoffset + 0;
p->to.type = D_CX;
} else {
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = tlsoffset + 0;
p->to.type = D_CX;
p->from.index = D_GS;
p->from.scale = 1;
}
break;
case Hplan9x32:
p->as = AMOVL;
p->from.type = D_EXTERN;
p->from.sym = plan9_tos;
p->to.type = D_CX;
p = appendp(p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = tlsoffset + 0;
p->to.type = D_CX;
break;
default:
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = tlsoffset + 0;
p->to.type = D_CX;
}
return p;
}
// Append code to p to check for stack split.
// Appends to (does not overwrite) p.
// Assumes g is in CX.
// Returns last new instruction.
// On return, *jmpok is the instruction that should jump
// to the stack frame allocation if no split is needed.
static Prog*
stacksplit(Prog *p, int32 framesize, Prog **jmpok)
{
Prog *q, *q1;
int arg;
if(debug['K']) {
// 8l -K means check not only for stack
// overflow but stack underflow.
// On underflow, INT 3 (breakpoint).
// Underflow itself is rare but this also
// catches out-of-sync stack guard info.
p = appendp(p);
p->as = ACMPL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 4;
p->to.type = D_SP;
p = appendp(p);
p->as = AJCC;
p->to.type = D_BRANCH;
p->to.offset = 4;
q1 = p;
p = appendp(p);
p->as = AINT;
p->from.type = D_CONST;
p->from.offset = 3;
p = appendp(p);
p->as = ANOP;
q1->pcond = p;
}
q1 = P;
if(framesize <= StackSmall) {
// small stack: SP <= stackguard
// CMPL SP, stackguard
p = appendp(p);
p->as = ACMPL;
p->from.type = D_SP;
p->to.type = D_INDIR+D_CX;
} else if(framesize <= StackBig) {
// large stack: SP-framesize <= stackguard-StackSmall
// LEAL -(framesize-StackSmall)(SP), AX
// CMPL AX, stackguard
p = appendp(p);
p->as = ALEAL;
p->from.type = D_INDIR+D_SP;
p->from.offset = -(framesize-StackSmall);
p->to.type = D_AX;
p = appendp(p);
p->as = ACMPL;
p->from.type = D_AX;
p->to.type = D_INDIR+D_CX;
} 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.
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// MOVL stackguard, CX
// CMPL CX, $StackPreempt
// JEQ label-of-call-to-morestack
// LEAL StackGuard(SP), AX
// SUBL stackguard, AX
// CMPL AX, $(framesize+(StackGuard-StackSmall))
p = appendp(p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_SI;
p = appendp(p);
p->as = ACMPL;
p->from.type = D_SI;
p->to.type = D_CONST;
p->to.offset = (uint32)StackPreempt;
p = appendp(p);
p->as = AJEQ;
p->to.type = D_BRANCH;
q1 = p;
p = appendp(p);
p->as = ALEAL;
p->from.type = D_INDIR+D_SP;
p->from.offset = StackGuard;
p->to.type = D_AX;
p = appendp(p);
p->as = ASUBL;
p->from.type = D_SI;
p->from.offset = 0;
p->to.type = D_AX;
p = appendp(p);
p->as = ACMPL;
p->from.type = D_AX;
p->to.type = D_CONST;
p->to.offset = framesize+(StackGuard-StackSmall);
}
// common
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
p->to.offset = 4;
q = p;
p = appendp(p); // save frame size in DI
p->as = AMOVL;
p->to.type = D_DI;
p->from.type = D_CONST;
// 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 + framesize + PtrSize + StackLimit >= StackMin)
p->from.offset = (framesize+7) & ~7LL;
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 = appendp(p); // save arg size in AX
p->as = AMOVL;
p->to.type = D_AX;
p->from.type = D_CONST;
p->from.offset = arg;
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = pmorestack;
p->to.sym = symmorestack;
p = appendp(p);
p->as = AJMP;
p->to.type = D_BRANCH;
p->pcond = cursym->text->link;
if(q != P)
q->pcond = p->link;
if(q1 != P)
q1->pcond = q->link;
*jmpok = 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;
}

View file

@ -1,173 +0,0 @@
// Inferno utils/8l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/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_EXTERN;
q->from.offset = n*4;
q->from.sym = s;
q->from.scale = 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 = AADDL;
p->from.type = D_CONST;
p->from.offset = 1;
p->to.type = 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_EXTERN;
q->from.sym = s;
q->from.scale = 4;
q->to.type = D_CONST;
q->to.offset = n;
s->type = SBSS;
s->size = 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(p->from.sym == s2) {
p->from.scale = 1;
ps2 = p;
}
if(p->from.sym == s4) {
p->from.scale = 1;
ps4 = p;
}
}
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
if(p->from.scale & NOPROF) /* dont profile */
continue;
/*
* JMPL profin
*/
q = prg();
q->line = p->line;
q->pc = p->pc;
q->link = p->link;
p->link = q;
p = q;
p->as = ACALL;
p->to.type = D_BRANCH;
p->pcond = ps2;
p->to.sym = s2;
for(; p; p=p->link) {
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;
/*
* JAL profout
*/
p->as = ACALL;
p->from = zprg.from;
p->to = zprg.to;
p->to.type = D_BRANCH;
p->pcond = ps4;
p->to.sym = s4;
p = q;
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -38,15 +38,14 @@
#include "../../pkg/runtime/mgc0.h"
void dynreloc(void);
static vlong addaddrplus4(Sym *s, Sym *t, vlong add);
/*
* divide-and-conquer list-link
* sort of Sym* structures.
* sort of LSym* structures.
* Used for the data block.
*/
int
datcmp(Sym *s1, Sym *s2)
datcmp(LSym *s1, LSym *s2)
{
if(s1->type != s2->type)
return (int)s1->type - (int)s2->type;
@ -58,11 +57,11 @@ datcmp(Sym *s1, Sym *s2)
return strcmp(s1->name, s2->name);
}
Sym*
listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
LSym*
listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off)
{
Sym *l1, *l2, *le;
#define NEXT(l) (*(Sym**)((char*)(l)+off))
LSym *l1, *l2, *le;
#define NEXT(l) (*(LSym**)((char*)(l)+off))
if(l == 0 || NEXT(l) == 0)
return l;
@ -128,31 +127,17 @@ listsort(Sym *l, int (*cmp)(Sym*, Sym*), int off)
#undef NEXT
}
Reloc*
addrel(Sym *s)
{
if(s->nr >= s->maxr) {
if(s->maxr == 0)
s->maxr = 4;
else
s->maxr <<= 1;
s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
}
return &s->r[s->nr++];
}
void
relocsym(Sym *s)
relocsym(LSym *s)
{
Reloc *r;
Sym *rs;
LSym *rs;
Prog p;
int32 i, off, siz, fl;
vlong o;
uchar *cast;
cursym = s;
ctxt->cursym = s;
memset(&p, 0, sizeof p);
for(r=s->r; r<s->r+s->nr; r++) {
r->done = 1;
@ -218,7 +203,7 @@ relocsym(Sym *s)
break;
case D_PCREL:
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != cursym->sect) {
if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) {
r->done = 0;
// set up addend for eventual relocation via outer symbol.
@ -264,7 +249,7 @@ relocsym(Sym *s)
//print("relocate %s %p %s => %p %p %p %p [%p]\n", s->name, s->value+off, r->sym ? r->sym->name : "<nil>", (void*)symaddr(r->sym), (void*)s->value, (void*)r->off, (void*)r->siz, (void*)o);
switch(siz) {
default:
cursym = s;
ctxt->cursym = s;
diag("bad reloc size %#ux for %s", siz, r->sym->name);
case 4:
if(r->type == D_PCREL) {
@ -291,27 +276,27 @@ relocsym(Sym *s)
void
reloc(void)
{
Sym *s;
LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
for(s=textp; s!=S; s=s->next)
for(s=ctxt->textp; s!=S; s=s->next)
relocsym(s);
for(s=datap; s!=S; s=s->next)
relocsym(s);
}
void
dynrelocsym(Sym *s)
dynrelocsym(LSym *s)
{
Reloc *r;
if(HEADTYPE == Hwindows) {
Sym *rel, *targ;
LSym *rel, *targ;
rel = lookup(".rel", 0);
rel = linklookup(ctxt, ".rel", 0);
if(s == rel)
return;
for(r=s->r; r<s->r+s->nr; r++) {
@ -323,17 +308,17 @@ dynrelocsym(Sym *s)
// jmp *addr
if(thechar == '8') {
adduint8(rel, 0xff);
adduint8(rel, 0x25);
addaddr(rel, targ);
adduint8(rel, 0x90);
adduint8(rel, 0x90);
adduint8(ctxt, rel, 0xff);
adduint8(ctxt, rel, 0x25);
addaddr(ctxt, rel, targ);
adduint8(ctxt, rel, 0x90);
adduint8(ctxt, rel, 0x90);
} else {
adduint8(rel, 0xff);
adduint8(rel, 0x24);
adduint8(rel, 0x25);
addaddrplus4(rel, targ, 0);
adduint8(rel, 0x90);
adduint8(ctxt, rel, 0xff);
adduint8(ctxt, rel, 0x24);
adduint8(ctxt, rel, 0x25);
addaddrplus4(ctxt, rel, targ, 0);
adduint8(ctxt, rel, 0x90);
}
} else if(r->sym->plt >= 0) {
r->sym = rel;
@ -352,7 +337,7 @@ dynrelocsym(Sym *s)
void
dynreloc(void)
{
Sym *s;
LSym *s;
// -d suppresses dynamic loader format, so we may as well not
// compute these sections or mark their symbols as reachable.
@ -362,7 +347,7 @@ dynreloc(void)
Bprint(&bso, "%5.2f reloc\n", cputime());
Bflush(&bso);
for(s=textp; s!=S; s=s->next)
for(s=ctxt->textp; s!=S; s=s->next)
dynrelocsym(s);
for(s=datap; s!=S; s=s->next)
dynrelocsym(s);
@ -370,118 +355,10 @@ dynreloc(void)
elfdynhash();
}
void
symgrow(Sym *s, int32 siz)
{
if(s->np >= siz)
return;
if(s->np > s->maxp) {
cursym = s;
diag("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
errorexit();
}
if(s->maxp < siz) {
if(s->maxp == 0)
s->maxp = 8;
while(s->maxp < siz)
s->maxp <<= 1;
s->p = erealloc(s->p, s->maxp);
memset(s->p+s->np, 0, s->maxp-s->np);
}
s->np = siz;
}
void
savedata(Sym *s, Prog *p, char *pn)
{
int32 off, siz, i, fl;
uchar *cast;
vlong o;
Reloc *r;
off = p->from.offset;
siz = p->datasize;
if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
mangle(pn);
symgrow(s, off+siz);
switch(p->to.type) {
default:
diag("bad data: %P", p);
break;
case D_FCONST:
switch(siz) {
default:
case 4:
fl = ieeedtof(&p->to.ieee);
cast = (uchar*)&fl;
for(i=0; i<4; i++)
s->p[off+i] = cast[fnuxi4[i]];
break;
case 8:
cast = (uchar*)&p->to.ieee;
for(i=0; i<8; i++)
s->p[off+i] = cast[fnuxi8[i]];
break;
}
break;
case D_SCONST:
for(i=0; i<siz; i++)
s->p[off+i] = p->to.scon[i];
break;
case D_CONST:
if(p->to.sym)
goto Addr;
o = p->to.offset;
fl = o;
cast = (uchar*)&fl;
switch(siz) {
default:
diag("bad nuxi %d\n%P", siz, p);
break;
case 1:
s->p[off] = cast[inuxi1[0]];
break;
case 2:
for(i=0; i<2; i++)
s->p[off+i] = cast[inuxi2[i]];
break;
case 4:
for(i=0; i<4; i++)
s->p[off+i] = cast[inuxi4[i]];
break;
case 8:
cast = (uchar*)&o;
for(i=0; i<8; i++)
s->p[off+i] = cast[inuxi8[i]];
break;
}
break;
case D_ADDR:
case D_SIZE:
Addr:
r = addrel(s);
r->off = off;
r->siz = siz;
r->sym = p->to.sym;
r->type = p->to.type;
if(r->type != D_SIZE)
r->type = D_ADDR;
r->add = p->to.offset;
break;
}
}
static void
blk(Sym *start, int32 addr, int32 size)
blk(LSym *start, int32 addr, int32 size)
{
Sym *sym;
LSym *sym;
int32 eaddr;
uchar *p, *ep;
@ -499,7 +376,7 @@ blk(Sym *start, int32 addr, int32 size)
diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
errorexit();
}
cursym = sym;
ctxt->cursym = sym;
for(; addr < sym->value; addr++)
cput(0);
p = sym->p;
@ -523,7 +400,7 @@ blk(Sym *start, int32 addr, int32 size)
void
codeblk(int32 addr, int32 size)
{
Sym *sym;
LSym *sym;
int32 eaddr, n, epc;
Prog *p;
uchar *q;
@ -531,13 +408,13 @@ codeblk(int32 addr, int32 size)
if(debug['a'])
Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
blk(textp, addr, size);
blk(ctxt->textp, addr, size);
/* again for printing */
if(!debug['a'])
return;
for(sym = textp; sym != nil; sym = sym->next) {
for(sym = ctxt->textp; sym != nil; sym = sym->next) {
if(!sym->reachable)
continue;
if(sym->value >= addr)
@ -600,7 +477,7 @@ codeblk(int32 addr, int32 size)
void
datblk(int32 addr, int32 size)
{
Sym *sym;
LSym *sym;
int32 i, eaddr;
uchar *p, *ep;
char *typ, *rsname;
@ -682,28 +559,28 @@ strnput(char *s, int n)
void
addstrdata(char *name, char *value)
{
Sym *s, *sp;
LSym *s, *sp;
char *p;
p = smprint("%s.str", name);
sp = lookup(p, 0);
sp = linklookup(ctxt, p, 0);
free(p);
addstring(sp, value);
s = lookup(name, 0);
s = linklookup(ctxt, name, 0);
s->size = 0;
s->dupok = 1;
addaddr(s, sp);
adduint32(s, strlen(value));
addaddr(ctxt, s, sp);
adduint32(ctxt, s, strlen(value));
if(PtrSize == 8)
adduint32(s, 0); // round struct to pointer width
adduint32(ctxt, s, 0); // round struct to pointer width
// in case reachability has already been computed
sp->reachable = s->reachable;
}
vlong
addstring(Sym *s, char *str)
addstring(LSym *s, char *str)
{
int n;
int32 r;
@ -715,230 +592,18 @@ addstring(Sym *s, char *str)
n = strlen(str)+1;
if(strcmp(s->name, ".shstrtab") == 0)
elfsetstring(str, r);
symgrow(s, r+n);
symgrow(ctxt, s, r+n);
memmove(s->p+r, str, n);
s->size += n;
return r;
}
vlong
setuintxx(Sym *s, vlong off, uint64 v, vlong wid)
{
int32 i, fl;
vlong o;
uchar *cast;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
if(s->size < off+wid) {
s->size = off+wid;
symgrow(s, s->size);
}
fl = v;
cast = (uchar*)&fl;
switch(wid) {
case 1:
s->p[off] = cast[inuxi1[0]];
break;
case 2:
for(i=0; i<2; i++)
s->p[off+i] = cast[inuxi2[i]];
break;
case 4:
for(i=0; i<4; i++)
s->p[off+i] = cast[inuxi4[i]];
break;
case 8:
o = v;
cast = (uchar*)&o;
for(i=0; i<8; i++)
s->p[off+i] = cast[inuxi8[i]];
break;
}
return off+wid;
}
vlong
adduintxx(Sym *s, uint64 v, int wid)
{
vlong off;
off = s->size;
setuintxx(s, off, v, wid);
return off;
}
vlong
adduint8(Sym *s, uint8 v)
{
return adduintxx(s, v, 1);
}
vlong
adduint16(Sym *s, uint16 v)
{
return adduintxx(s, v, 2);
}
vlong
adduint32(Sym *s, uint32 v)
{
return adduintxx(s, v, 4);
}
vlong
adduint64(Sym *s, uint64 v)
{
return adduintxx(s, v, 8);
}
vlong
setuint8(Sym *s, vlong r, uint8 v)
{
return setuintxx(s, r, v, 1);
}
vlong
setuint16(Sym *s, vlong r, uint16 v)
{
return setuintxx(s, r, v, 2);
}
vlong
setuint32(Sym *s, vlong r, uint32 v)
{
return setuintxx(s, r, v, 4);
}
vlong
setuint64(Sym *s, vlong r, uint64 v)
{
return setuintxx(s, r, v, 8);
}
vlong
addaddrplus(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += PtrSize;
symgrow(s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = PtrSize;
r->type = D_ADDR;
r->add = add;
return i + r->siz;
}
static vlong
addaddrplus4(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += 4;
symgrow(s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = 4;
r->type = D_ADDR;
r->add = add;
return i + r->siz;
}
vlong
addpcrelplus(Sym *s, Sym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += 4;
symgrow(s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->add = add;
r->type = D_PCREL;
r->siz = 4;
return i + r->siz;
}
vlong
addaddr(Sym *s, Sym *t)
{
return addaddrplus(s, t, 0);
}
vlong
setaddrplus(Sym *s, vlong off, Sym *t, vlong add)
{
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
if(off+PtrSize > s->size) {
s->size = off + PtrSize;
symgrow(s, s->size);
}
r = addrel(s);
r->sym = t;
r->off = off;
r->siz = PtrSize;
r->type = D_ADDR;
r->add = add;
return off + r->siz;
}
vlong
setaddr(Sym *s, vlong off, Sym *t)
{
return setaddrplus(s, off, t, 0);
}
vlong
addsize(Sym *s, Sym *t)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += PtrSize;
symgrow(s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = PtrSize;
r->type = D_SIZE;
return i + r->siz;
}
void
dosymtype(void)
{
Sym *s;
LSym *s;
for(s = allsym; s != nil; s = s->allsym) {
for(s = ctxt->allsym; s != nil; s = s->allsym) {
if(s->np > 0) {
if(s->type == SBSS)
s->type = SDATA;
@ -949,7 +614,7 @@ dosymtype(void)
}
static int32
symalign(Sym *s)
symalign(LSym *s)
{
int32 align;
@ -965,7 +630,7 @@ symalign(Sym *s)
}
static vlong
aligndatsize(vlong datsize, Sym *s)
aligndatsize(vlong datsize, LSym *s)
{
return rnd(datsize, symalign(s));
}
@ -973,7 +638,7 @@ aligndatsize(vlong datsize, Sym *s)
// maxalign returns the maximum required alignment for
// the list of symbols s; the list stops when s->type exceeds type.
static int32
maxalign(Sym *s, int type)
maxalign(LSym *s, int type)
{
int32 align, max;
@ -987,10 +652,10 @@ maxalign(Sym *s, int type)
}
static void
gcaddsym(Sym *gc, Sym *s, vlong off)
gcaddsym(LSym *gc, LSym *s, vlong off)
{
vlong a;
Sym *gotype;
LSym *gotype;
if(s->size < PtrSize)
return;
@ -1000,22 +665,22 @@ gcaddsym(Sym *gc, Sym *s, vlong off)
gotype = s->gotype;
if(gotype != nil) {
//print("gcaddsym: %s %d %s\n", s->name, s->size, gotype->name);
adduintxx(gc, GC_CALL, PtrSize);
adduintxx(gc, off, PtrSize);
addpcrelplus(gc, decodetype_gc(gotype), 3*PtrSize+4);
adduintxx(ctxt, gc, GC_CALL, PtrSize);
adduintxx(ctxt, gc, off, PtrSize);
addpcrelplus(ctxt, gc, decodetype_gc(gotype), 3*PtrSize+4);
if(PtrSize == 8)
adduintxx(gc, 0, 4);
adduintxx(ctxt, gc, 0, 4);
} else {
//print("gcaddsym: %s %d <unknown type>\n", s->name, s->size);
for(a = -off&(PtrSize-1); a+PtrSize<=s->size; a+=PtrSize) {
adduintxx(gc, GC_APTR, PtrSize);
adduintxx(gc, off+a, PtrSize);
adduintxx(ctxt, gc, GC_APTR, PtrSize);
adduintxx(ctxt, gc, off+a, PtrSize);
}
}
}
void
growdatsize(vlong *datsizep, Sym *s)
growdatsize(vlong *datsizep, LSym *s)
{
vlong datsize;
@ -1034,24 +699,24 @@ dodata(void)
vlong datsize;
Section *sect;
Segment *segro;
Sym *s, *last, **l;
Sym *gcdata1, *gcbss1;
LSym *s, *last, **l;
LSym *gcdata1, *gcbss1;
if(debug['v'])
Bprint(&bso, "%5.2f dodata\n", cputime());
Bflush(&bso);
gcdata1 = lookup("gcdata", 0);
gcbss1 = lookup("gcbss", 0);
gcdata1 = linklookup(ctxt, "gcdata", 0);
gcbss1 = linklookup(ctxt, "gcbss", 0);
// size of .data and .bss section. the zero value is later replaced by the actual size of the section.
adduintxx(gcdata1, 0, PtrSize);
adduintxx(gcbss1, 0, PtrSize);
adduintxx(ctxt, gcdata1, 0, PtrSize);
adduintxx(ctxt, gcbss1, 0, PtrSize);
last = nil;
datap = nil;
for(s=allsym; s!=S; s=s->allsym) {
for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(!s->reachable || s->special)
continue;
if(STEXT < s->type && s->type < SXREF) {
@ -1092,7 +757,7 @@ dodata(void)
}
*l = nil;
datap = listsort(datap, datcmp, offsetof(Sym, next));
datap = listsort(datap, datcmp, offsetof(LSym, next));
/*
* allocate sections. list is sorted by type,
@ -1128,8 +793,8 @@ dodata(void)
sect->align = maxalign(s, SINITARR-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("noptrdata", 0)->sect = sect;
lookup("enoptrdata", 0)->sect = sect;
linklookup(ctxt, "noptrdata", 0)->sect = sect;
linklookup(ctxt, "enoptrdata", 0)->sect = sect;
for(; s != nil && s->type < SINITARR; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1159,11 +824,11 @@ dodata(void)
sect->align = maxalign(s, SBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("data", 0)->sect = sect;
lookup("edata", 0)->sect = sect;
linklookup(ctxt, "data", 0)->sect = sect;
linklookup(ctxt, "edata", 0)->sect = sect;
for(; s != nil && s->type < SBSS; s = s->next) {
if(s->type == SINITARR) {
cursym = s;
ctxt->cursym = s;
diag("unexpected symbol type %d", s->type);
}
s->sect = sect;
@ -1175,16 +840,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
adduintxx(gcdata1, GC_END, PtrSize);
setuintxx(gcdata1, 0, sect->len, PtrSize);
adduintxx(ctxt, gcdata1, GC_END, PtrSize);
setuintxx(ctxt, gcdata1, 0, sect->len, PtrSize);
/* bss */
sect = addsection(&segdata, ".bss", 06);
sect->align = maxalign(s, SNOPTRBSS-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("bss", 0)->sect = sect;
lookup("ebss", 0)->sect = sect;
linklookup(ctxt, "bss", 0)->sect = sect;
linklookup(ctxt, "ebss", 0)->sect = sect;
for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
s->sect = sect;
datsize = aligndatsize(datsize, s);
@ -1194,16 +859,16 @@ dodata(void)
}
sect->len = datsize - sect->vaddr;
adduintxx(gcbss1, GC_END, PtrSize);
setuintxx(gcbss1, 0, sect->len, PtrSize);
adduintxx(ctxt, gcbss1, GC_END, PtrSize);
setuintxx(ctxt, gcbss1, 0, sect->len, PtrSize);
/* pointer-free bss */
sect = addsection(&segdata, ".noptrbss", 06);
sect->align = maxalign(s, SNOPTRBSS);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("noptrbss", 0)->sect = sect;
lookup("enoptrbss", 0)->sect = sect;
linklookup(ctxt, "noptrbss", 0)->sect = sect;
linklookup(ctxt, "enoptrbss", 0)->sect = sect;
for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1211,7 +876,7 @@ dodata(void)
growdatsize(&datsize, s);
}
sect->len = datsize - sect->vaddr;
lookup("end", 0)->sect = sect;
linklookup(ctxt, "end", 0)->sect = sect;
// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
if(datsize != (uint32)datsize) {
@ -1233,7 +898,7 @@ dodata(void)
}
if(s != nil) {
cursym = nil;
ctxt->cursym = nil;
diag("unexpected symbol type %d for %s", s->type, s->name);
}
@ -1274,8 +939,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = 0;
lookup("rodata", 0)->sect = sect;
lookup("erodata", 0)->sect = sect;
linklookup(ctxt, "rodata", 0)->sect = sect;
linklookup(ctxt, "erodata", 0)->sect = sect;
for(; s != nil && s->type < STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1290,8 +955,8 @@ dodata(void)
sect->align = maxalign(s, STYPELINK);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("typelink", 0)->sect = sect;
lookup("etypelink", 0)->sect = sect;
linklookup(ctxt, "typelink", 0)->sect = sect;
linklookup(ctxt, "etypelink", 0)->sect = sect;
for(; s != nil && s->type == STYPELINK; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1306,8 +971,8 @@ dodata(void)
sect->align = maxalign(s, SPCLNTAB-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("symtab", 0)->sect = sect;
lookup("esymtab", 0)->sect = sect;
linklookup(ctxt, "symtab", 0)->sect = sect;
linklookup(ctxt, "esymtab", 0)->sect = sect;
for(; s != nil && s->type < SPCLNTAB; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1322,8 +987,8 @@ dodata(void)
sect->align = maxalign(s, SELFROSECT-1);
datsize = rnd(datsize, sect->align);
sect->vaddr = datsize;
lookup("pclntab", 0)->sect = sect;
lookup("epclntab", 0)->sect = sect;
linklookup(ctxt, "pclntab", 0)->sect = sect;
linklookup(ctxt, "epclntab", 0)->sect = sect;
for(; s != nil && s->type < SELFROSECT; s = s->next) {
datsize = aligndatsize(datsize, s);
s->sect = sect;
@ -1368,7 +1033,7 @@ textaddress(void)
uvlong va;
Prog *p;
Section *sect;
Sym *sym, *sub;
LSym *sym, *sub;
addsection(&segtext, ".text", 05);
@ -1377,11 +1042,11 @@ textaddress(void)
// and then letting threads copy down, but probably not worth it.
sect = segtext.sect;
sect->align = FuncAlign;
lookup("text", 0)->sect = sect;
lookup("etext", 0)->sect = sect;
linklookup(ctxt, "text", 0)->sect = sect;
linklookup(ctxt, "etext", 0)->sect = sect;
va = INITTEXT;
sect->vaddr = va;
for(sym = textp; sym != nil; sym = sym->next) {
for(sym = ctxt->textp; sym != nil; sym = sym->next) {
sym->sect = sect;
if(sym->type & SSUB)
continue;
@ -1396,7 +1061,7 @@ textaddress(void)
p->pc += sub->value;
}
if(sym->size == 0 && sym->sub != S) {
cursym = sym;
ctxt->cursym = sym;
}
va += sym->size;
}
@ -1409,7 +1074,7 @@ address(void)
{
Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
Section *typelink;
Sym *sym, *sub;
LSym *sym, *sub;
uvlong va;
vlong vlen;
@ -1451,7 +1116,7 @@ address(void)
segdata.filelen = 0;
if(HEADTYPE == Hwindows)
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
if(HEADTYPE == Hplan9x64 || HEADTYPE == Hplan9x32)
if(HEADTYPE == Hplan9)
segdata.fileoff = segtext.fileoff + segtext.filelen;
data = nil;
noptr = nil;
@ -1485,7 +1150,7 @@ address(void)
pclntab = symtab->next;
for(sym = datap; sym != nil; sym = sym->next) {
cursym = sym;
ctxt->cursym = sym;
sym->value += sym->sect->vaddr;
for(sub = sym->sub; sub != nil; sub = sub->sub)
sub->value += sym->value;
@ -1498,13 +1163,13 @@ address(void)
xdefine("typelink", SRODATA, typelink->vaddr);
xdefine("etypelink", SRODATA, typelink->vaddr + typelink->len);
sym = lookup("gcdata", 0);
sym = linklookup(ctxt, "gcdata", 0);
xdefine("egcdata", SRODATA, symaddr(sym) + sym->size);
lookup("egcdata", 0)->sect = sym->sect;
linklookup(ctxt, "egcdata", 0)->sect = sym->sect;
sym = lookup("gcbss", 0);
sym = linklookup(ctxt, "gcbss", 0);
xdefine("egcbss", SRODATA, symaddr(sym) + sym->size);
lookup("egcbss", 0)->sect = sym->sect;
linklookup(ctxt, "egcbss", 0)->sect = sym->sect;
xdefine("symtab", SRODATA, symtab->vaddr);
xdefine("esymtab", SRODATA, symtab->vaddr + symtab->len);

View file

@ -11,7 +11,7 @@
// ../gc/reflect.c stuffs in these.
static Reloc*
decode_reloc(Sym *s, int32 off)
decode_reloc(LSym *s, int32 off)
{
int i;
@ -21,8 +21,8 @@ decode_reloc(Sym *s, int32 off)
return nil;
}
static Sym*
decode_reloc_sym(Sym *s, int32 off)
static LSym*
decode_reloc_sym(LSym *s, int32 off)
{
Reloc *r;
@ -69,86 +69,86 @@ decode_inuxi(uchar* p, int sz)
// Type.commonType.kind
uint8
decodetype_kind(Sym *s)
decodetype_kind(LSym *s)
{
return s->p[1*PtrSize + 7] & ~KindNoPointers; // 0x13 / 0x1f
}
// Type.commonType.size
vlong
decodetype_size(Sym *s)
decodetype_size(LSym *s)
{
return decode_inuxi(s->p, PtrSize); // 0x8 / 0x10
}
// Type.commonType.gc
Sym*
decodetype_gc(Sym *s)
LSym*
decodetype_gc(LSym *s)
{
return decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
}
// Type.ArrayType.elem and Type.SliceType.Elem
Sym*
decodetype_arrayelem(Sym *s)
LSym*
decodetype_arrayelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
vlong
decodetype_arraylen(Sym *s)
decodetype_arraylen(LSym *s)
{
return decode_inuxi(s->p + CommonSize+PtrSize, PtrSize);
}
// Type.PtrType.elem
Sym*
decodetype_ptrelem(Sym *s)
LSym*
decodetype_ptrelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
// Type.MapType.key, elem
Sym*
decodetype_mapkey(Sym *s)
LSym*
decodetype_mapkey(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
Sym*
decodetype_mapvalue(Sym *s)
LSym*
decodetype_mapvalue(LSym *s)
{
return decode_reloc_sym(s, CommonSize+PtrSize); // 0x20 / 0x38
}
// Type.ChanType.elem
Sym*
decodetype_chanelem(Sym *s)
LSym*
decodetype_chanelem(LSym *s)
{
return decode_reloc_sym(s, CommonSize); // 0x1c / 0x30
}
// Type.FuncType.dotdotdot
int
decodetype_funcdotdotdot(Sym *s)
decodetype_funcdotdotdot(LSym *s)
{
return s->p[CommonSize];
}
// Type.FuncType.in.len
int
decodetype_funcincount(Sym *s)
decodetype_funcincount(LSym *s)
{
return decode_inuxi(s->p + CommonSize+2*PtrSize, IntSize);
}
int
decodetype_funcoutcount(Sym *s)
decodetype_funcoutcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize+3*PtrSize + 2*IntSize, IntSize);
}
Sym*
decodetype_funcintype(Sym *s, int i)
LSym*
decodetype_funcintype(LSym *s, int i)
{
Reloc *r;
@ -158,8 +158,8 @@ decodetype_funcintype(Sym *s, int i)
return decode_reloc_sym(r->sym, r->add + i * PtrSize);
}
Sym*
decodetype_funcouttype(Sym *s, int i)
LSym*
decodetype_funcouttype(LSym *s, int i)
{
Reloc *r;
@ -171,7 +171,7 @@ decodetype_funcouttype(Sym *s, int i)
// Type.StructType.fields.Slice::len
int
decodetype_structfieldcount(Sym *s)
decodetype_structfieldcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
}
@ -181,7 +181,7 @@ enum {
};
// Type.StructType.fields[]-> name, typ and offset.
char*
decodetype_structfieldname(Sym *s, int i)
decodetype_structfieldname(LSym *s, int i)
{
Reloc *r;
@ -195,21 +195,21 @@ decodetype_structfieldname(Sym *s, int i)
return (char*) r->sym->p + r->add; // the c-string
}
Sym*
decodetype_structfieldtype(Sym *s, int i)
LSym*
decodetype_structfieldtype(LSym *s, int i)
{
return decode_reloc_sym(s, CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 2*PtrSize);
}
vlong
decodetype_structfieldoffs(Sym *s, int i)
decodetype_structfieldoffs(LSym *s, int i)
{
return decode_inuxi(s->p + CommonSize + PtrSize + 2*IntSize + i*StructFieldSize + 4*PtrSize, IntSize);
}
// InterfaceTYpe.methods.len
vlong
decodetype_ifacemethodcount(Sym *s)
decodetype_ifacemethodcount(LSym *s)
{
return decode_inuxi(s->p + CommonSize + PtrSize, IntSize);
}

View file

@ -27,19 +27,19 @@
static vlong abbrevo;
static vlong abbrevsize;
static Sym* abbrevsym;
static LSym* abbrevsym;
static vlong abbrevsympos;
static vlong lineo;
static vlong linesize;
static Sym* linesym;
static LSym* linesym;
static vlong linesympos;
static vlong infoo; // also the base for DWDie->offs and reference attributes.
static vlong infosize;
static Sym* infosym;
static LSym* infosym;
static vlong infosympos;
static vlong frameo;
static vlong framesize;
static Sym* framesym;
static LSym* framesym;
static vlong framesympos;
static vlong pubnameso;
static vlong pubnamessize;
@ -50,19 +50,19 @@ static vlong arangessize;
static vlong gdbscripto;
static vlong gdbscriptsize;
static Sym *infosec;
static LSym *infosec;
static vlong inforeloco;
static vlong inforelocsize;
static Sym *arangessec;
static LSym *arangessec;
static vlong arangesreloco;
static vlong arangesrelocsize;
static Sym *linesec;
static LSym *linesec;
static vlong linereloco;
static vlong linerelocsize;
static Sym *framesec;
static LSym *framesec;
static vlong framereloco;
static vlong framerelocsize;
@ -594,7 +594,7 @@ find_or_diag(DWDie *die, char* name)
}
static void
adddwarfrel(Sym* sec, Sym* sym, vlong offsetbase, int siz, vlong addend)
adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
{
Reloc *r;
@ -639,8 +639,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
switch(form) {
case DW_FORM_addr: // address
if(linkmode == LinkExternal) {
value -= ((Sym*)data)->value;
adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
value -= ((LSym*)data)->value;
adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@ -651,8 +651,8 @@ putattr(int abbrev, int form, int cls, vlong value, char *data)
cput(1+PtrSize);
cput(DW_OP_addr);
if(linkmode == LinkExternal) {
value -= ((Sym*)data)->value;
adddwarfrel(infosec, (Sym*)data, infoo, PtrSize, value);
value -= ((LSym*)data)->value;
adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
break;
}
addrput(value);
@ -847,7 +847,7 @@ newmemberoffsetattr(DWDie *die, int32 offs)
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
// location expression that evals to a const.
static void
newabslocexprattr(DWDie *die, vlong addr, Sym *sym)
newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
{
newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
}
@ -864,12 +864,12 @@ enum {
static DWDie* defptrto(DWDie *dwtype); // below
// Lookup predefined types
static Sym*
static LSym*
lookup_or_diag(char *n)
{
Sym *s;
LSym *s;
s = rlookup(n, 0);
s = linkrlookup(ctxt, n, 0);
if (s == nil || s->size == 0) {
diag("dwarf: missing type: %s", n);
errorexit();
@ -904,10 +904,10 @@ dotypedef(DWDie *parent, char *name, DWDie *def)
// Define gotype, for composite ones recurse into constituents.
static DWDie*
defgotype(Sym *gotype)
defgotype(LSym *gotype)
{
DWDie *die, *fld;
Sym *s;
LSym *s;
char *name, *f;
uint8 kind;
vlong bytesize;
@ -1335,7 +1335,7 @@ synthesizechantypes(DWDie *die)
// For use with pass.c::genasmsym
static void
defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
{
DWDie *dv, *dt;
@ -1607,7 +1607,7 @@ inithist(Auto *a)
absline = a->aoffset;
} else if (a->type == D_FILE1) { // 'Z'
// We could just fixup the current
// linehist->line, but there doesn't appear to
// linehist->lineno, but there doesn't appear to
// be a guarantee that every 'Z' is preceded
// by its own 'z', so do the safe thing and
// update the stack and push a new Linehist
@ -1719,7 +1719,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
flushunit(DWDie *dwinfo, vlong pc, Sym *pcsym, vlong unitstart, int32 header_length)
flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
{
vlong here;
@ -1745,7 +1745,7 @@ static void
writelines(void)
{
Prog *q;
Sym *s, *epcs;
LSym *s, *epcs;
Auto *a;
vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
@ -1757,7 +1757,7 @@ writelines(void)
char *n, *nn;
if(linesec == S)
linesec = lookup(".dwarfline", 0);
linesec = linklookup(ctxt, ".dwarfline", 0);
linesec->nr = 0;
unitstart = -1;
@ -1771,8 +1771,8 @@ writelines(void)
lineo = cpos();
dwinfo = nil;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
s = cursym;
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
if(s->text == P)
continue;
@ -1859,7 +1859,7 @@ writelines(void)
continue;
for(q = s->text; q != P; q = q->link) {
lh = searchhist(q->line);
lh = searchhist(q->lineno);
if (lh == nil) {
diag("dwarf: corrupt history or bad absolute line: %P", q);
continue;
@ -1870,11 +1870,11 @@ writelines(void)
continue;
}
lline = lh->line + q->line - lh->absline;
lline = lh->line + q->lineno - lh->absline;
if (debug['v'] > 1)
print("%6llux %s[%lld] %P\n", (vlong)q->pc, histfile[lh->file], lline, q);
if (q->line == lc)
if (q->lineno == lc)
continue;
if (currfile != lh->file) {
currfile = lh->file;
@ -1883,7 +1883,7 @@ writelines(void)
}
putpclcdelta(q->pc - pc, lline - llc);
pc = q->pc;
lc = q->line;
lc = q->lineno;
llc = lline;
}
@ -1971,11 +1971,11 @@ static void
writeframes(void)
{
Prog *p, *q;
Sym *s;
LSym *s;
vlong fdeo, fdesize, pad, cfa, pc;
if(framesec == S)
framesec = lookup(".dwarfframe", 0);
framesec = linklookup(ctxt, ".dwarfframe", 0);
framesec->nr = 0;
frameo = cpos();
@ -2003,8 +2003,8 @@ writeframes(void)
}
strnput("", pad);
for(cursym = textp; cursym != nil; cursym = cursym->next) {
s = cursym;
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
s = ctxt->cursym;
if(s->text == nil)
continue;
@ -2067,11 +2067,11 @@ writeinfo(void)
fwdcount = 0;
if (infosec == S)
infosec = lookup(".dwarfinfo", 0);
infosec = linklookup(ctxt, ".dwarfinfo", 0);
infosec->nr = 0;
if(arangessec == S)
arangessec = lookup(".dwarfaranges", 0);
arangessec = linklookup(ctxt, ".dwarfaranges", 0);
arangessec->nr = 0;
for (compunit = dwroot.child; compunit; compunit = compunit->link) {
@ -2204,7 +2204,7 @@ writearanges(void)
strnput("", headersize - (4+2+4+1+1)); // align to PtrSize
if(linkmode == LinkExternal)
adddwarfrel(arangessec, (Sym*)b->data, sectionstart, PtrSize, b->value-((Sym*)b->data)->value);
adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
else
addrput(b->value);
@ -2239,7 +2239,7 @@ align(vlong size)
}
static vlong
writedwarfreloc(Sym* s)
writedwarfreloc(LSym* s)
{
int i;
vlong start;
@ -2408,7 +2408,7 @@ enum
vlong elfstrdbg[NElfStrDbg];
void
dwarfaddshstrings(Sym *shstrtab)
dwarfaddshstrings(LSym *shstrtab)
{
if(debug['w']) // disable dwarf
return;
@ -2438,16 +2438,16 @@ dwarfaddshstrings(Sym *shstrtab)
elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
}
infosym = lookup(".debug_info", 0);
infosym = linklookup(ctxt, ".debug_info", 0);
infosym->hide = 1;
abbrevsym = lookup(".debug_abbrev", 0);
abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
abbrevsym->hide = 1;
linesym = lookup(".debug_line", 0);
linesym = linklookup(ctxt, ".debug_line", 0);
linesym->hide = 1;
framesym = lookup(".debug_frame", 0);
framesym = linklookup(ctxt, ".debug_frame", 0);
framesym->hide = 1;
}
}

View file

@ -19,7 +19,7 @@ void dwarfemitdebugsections(void);
* s[ection]h[eader]str[ing]tab. Prerequisite for
* dwarfaddelfheaders().
*/
void dwarfaddshstrings(Sym *shstrtab);
void dwarfaddshstrings(LSym *shstrtab);
/*
* Add section headers pointing to the sections emitted in

View file

@ -287,35 +287,35 @@ elfhash(uchar *name)
}
void
elfwritedynent(Sym *s, int tag, uint64 val)
elfwritedynent(LSym *s, int tag, uint64 val)
{
if(elf64) {
adduint64(s, tag);
adduint64(s, val);
adduint64(ctxt, s, tag);
adduint64(ctxt, s, val);
} else {
adduint32(s, tag);
adduint32(s, val);
adduint32(ctxt, s, tag);
adduint32(ctxt, s, val);
}
}
void
elfwritedynentsym(Sym *s, int tag, Sym *t)
elfwritedynentsym(LSym *s, int tag, LSym *t)
{
if(elf64)
adduint64(s, tag);
adduint64(ctxt, s, tag);
else
adduint32(s, tag);
addaddr(s, t);
adduint32(ctxt, s, tag);
addaddr(ctxt, s, t);
}
void
elfwritedynentsymsize(Sym *s, int tag, Sym *t)
elfwritedynentsymsize(LSym *s, int tag, LSym *t)
{
if(elf64)
adduint64(s, tag);
adduint64(ctxt, s, tag);
else
adduint32(s, tag);
addsize(s, t);
adduint32(ctxt, s, tag);
addsize(ctxt, s, t);
}
int
@ -561,7 +561,7 @@ haveaux:
void
elfdynhash(void)
{
Sym *s, *sy, *dynstr;
LSym *s, *sy, *dynstr;
int i, j, nbucket, b, nfile;
uint32 hc, *chain, *buckets;
int nsym;
@ -575,7 +575,7 @@ elfdynhash(void)
return;
nsym = nelfsym;
s = lookup(".hash", 0);
s = linklookup(ctxt, ".hash", 0);
s->type = SELFROSECT;
s->reachable = 1;
@ -591,14 +591,14 @@ elfdynhash(void)
chain = malloc(nsym * sizeof chain[0]);
buckets = malloc(nbucket * sizeof buckets[0]);
if(need == nil || chain == nil || buckets == nil) {
cursym = nil;
ctxt->cursym = nil;
diag("out of memory");
errorexit();
}
memset(need, 0, nsym * sizeof need[0]);
memset(chain, 0, nsym * sizeof chain[0]);
memset(buckets, 0, nbucket * sizeof buckets[0]);
for(sy=allsym; sy!=S; sy=sy->allsym) {
for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
if (sy->dynid <= 0)
continue;
@ -613,69 +613,69 @@ elfdynhash(void)
buckets[b] = sy->dynid;
}
adduint32(s, nbucket);
adduint32(s, nsym);
adduint32(ctxt, s, nbucket);
adduint32(ctxt, s, nsym);
for(i = 0; i<nbucket; i++)
adduint32(s, buckets[i]);
adduint32(ctxt, s, buckets[i]);
for(i = 0; i<nsym; i++)
adduint32(s, chain[i]);
adduint32(ctxt, s, chain[i]);
free(chain);
free(buckets);
// version symbols
dynstr = lookup(".dynstr", 0);
s = lookup(".gnu.version_r", 0);
dynstr = linklookup(ctxt, ".dynstr", 0);
s = linklookup(ctxt, ".gnu.version_r", 0);
i = 2;
nfile = 0;
for(l=needlib; l; l=l->next) {
nfile++;
// header
adduint16(s, 1); // table version
adduint16(ctxt, s, 1); // table version
j = 0;
for(x=l->aux; x; x=x->next)
j++;
adduint16(s, j); // aux count
adduint32(s, addstring(dynstr, l->file)); // file string offset
adduint32(s, 16); // offset from header to first aux
adduint16(ctxt, s, j); // aux count
adduint32(ctxt, s, addstring(dynstr, l->file)); // file string offset
adduint32(ctxt, s, 16); // offset from header to first aux
if(l->next)
adduint32(s, 16+j*16); // offset from this header to next
adduint32(ctxt, s, 16+j*16); // offset from this header to next
else
adduint32(s, 0);
adduint32(ctxt, s, 0);
for(x=l->aux; x; x=x->next) {
x->num = i++;
// aux struct
adduint32(s, elfhash((uchar*)x->vers)); // hash
adduint16(s, 0); // flags
adduint16(s, x->num); // other - index we refer to this by
adduint32(s, addstring(dynstr, x->vers)); // version string offset
adduint32(ctxt, s, elfhash((uchar*)x->vers)); // hash
adduint16(ctxt, s, 0); // flags
adduint16(ctxt, s, x->num); // other - index we refer to this by
adduint32(ctxt, s, addstring(dynstr, x->vers)); // version string offset
if(x->next)
adduint32(s, 16); // offset from this aux to next
adduint32(ctxt, s, 16); // offset from this aux to next
else
adduint32(s, 0);
adduint32(ctxt, s, 0);
}
}
// version references
s = lookup(".gnu.version", 0);
s = linklookup(ctxt, ".gnu.version", 0);
for(i=0; i<nsym; i++) {
if(i == 0)
adduint16(s, 0); // first entry - no symbol
adduint16(ctxt, s, 0); // first entry - no symbol
else if(need[i] == nil)
adduint16(s, 1); // global
adduint16(ctxt, s, 1); // global
else
adduint16(s, need[i]->num);
adduint16(ctxt, s, need[i]->num);
}
free(need);
s = lookup(".dynamic", 0);
s = linklookup(ctxt, ".dynamic", 0);
elfverneed = nfile;
if(elfverneed) {
elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
elfwritedynent(s, DT_VERNEEDNUM, nfile);
elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
}
elfwritedynent(s, DT_NULL, 0);
}
@ -807,9 +807,9 @@ elfshreloc(Section *sect)
}
void
elfrelocsect(Section *sect, Sym *first)
elfrelocsect(Section *sect, LSym *first)
{
Sym *sym;
LSym *sym;
int32 eaddr;
Reloc *r;
@ -834,7 +834,7 @@ elfrelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
cursym = sym;
ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@ -861,7 +861,7 @@ elfemitreloc(void)
while(cpos()&7)
cput(0);
elfrelocsect(segtext.sect, textp);
elfrelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
elfrelocsect(sect, datap);
for(sect=segrodata.sect; sect!=nil; sect=sect->next)
@ -873,13 +873,13 @@ elfemitreloc(void)
void
doelf(void)
{
Sym *s, *shstrtab, *dynstr;
LSym *s, *shstrtab, *dynstr;
if(!iself)
return;
/* predefine strings we need for section headers */
shstrtab = lookup(".shstrtab", 0);
shstrtab = linklookup(ctxt, ".shstrtab", 0);
shstrtab->type = SELFROSECT;
shstrtab->reachable = 1;
@ -969,7 +969,7 @@ doelf(void)
addstring(shstrtab, ".gnu.version_r");
/* dynamic symbol table - first entry all zeros */
s = lookup(".dynsym", 0);
s = linklookup(ctxt, ".dynsym", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(thechar == '6')
@ -978,7 +978,7 @@ doelf(void)
s->size += ELF32SYMSIZE;
/* dynamic string table */
s = lookup(".dynstr", 0);
s = linklookup(ctxt, ".dynstr", 0);
s->type = SELFROSECT;
s->reachable = 1;
if(s->size == 0)
@ -987,85 +987,85 @@ doelf(void)
/* relocation table */
if(thechar == '6')
s = lookup(".rela", 0);
s = linklookup(ctxt, ".rela", 0);
else
s = lookup(".rel", 0);
s = linklookup(ctxt, ".rel", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* global offset table */
s = lookup(".got", 0);
s = linklookup(ctxt, ".got", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/* hash */
s = lookup(".hash", 0);
s = linklookup(ctxt, ".hash", 0);
s->reachable = 1;
s->type = SELFROSECT;
s = lookup(".got.plt", 0);
s = linklookup(ctxt, ".got.plt", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
s = lookup(".plt", 0);
s = linklookup(ctxt, ".plt", 0);
s->reachable = 1;
s->type = SELFRXSECT;
elfsetupplt();
if(thechar == '6')
s = lookup(".rela.plt", 0);
s = linklookup(ctxt, ".rela.plt", 0);
else
s = lookup(".rel.plt", 0);
s = linklookup(ctxt, ".rel.plt", 0);
s->reachable = 1;
s->type = SELFROSECT;
s = lookup(".gnu.version", 0);
s = linklookup(ctxt, ".gnu.version", 0);
s->reachable = 1;
s->type = SELFROSECT;
s = lookup(".gnu.version_r", 0);
s = linklookup(ctxt, ".gnu.version_r", 0);
s->reachable = 1;
s->type = SELFROSECT;
/* define dynamic elf table */
s = lookup(".dynamic", 0);
s = linklookup(ctxt, ".dynamic", 0);
s->reachable = 1;
s->type = SELFSECT; // writable
/*
* .dynamic table
*/
elfwritedynentsym(s, DT_HASH, lookup(".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, lookup(".dynsym", 0));
elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
if(thechar == '6')
elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
else
elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
elfwritedynentsym(s, DT_STRTAB, lookup(".dynstr", 0));
elfwritedynentsymsize(s, DT_STRSZ, lookup(".dynstr", 0));
elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
if(thechar == '6') {
elfwritedynentsym(s, DT_RELA, lookup(".rela", 0));
elfwritedynentsymsize(s, DT_RELASZ, lookup(".rela", 0));
elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
} else {
elfwritedynentsym(s, DT_REL, lookup(".rel", 0));
elfwritedynentsymsize(s, DT_RELSZ, lookup(".rel", 0));
elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
}
if(rpath)
elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
elfwritedynentsym(s, DT_PLTGOT, lookup(".got.plt", 0));
elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
if(thechar == '6') {
elfwritedynent(s, DT_PLTREL, DT_RELA);
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rela.plt", 0));
elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rela.plt", 0));
} else {
elfwritedynent(s, DT_PLTREL, DT_REL);
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
elfwritedynentsymsize(s, DT_PLTRELSZ, linklookup(ctxt, ".rel.plt", 0));
elfwritedynentsym(s, DT_JMPREL, linklookup(ctxt, ".rel.plt", 0));
}
elfwritedynent(s, DT_DEBUG, 0);
@ -1075,7 +1075,7 @@ doelf(void)
}
void
shsym(ElfShdr *sh, Sym *s)
shsym(ElfShdr *sh, LSym *s)
{
vlong addr;
addr = symaddr(s);
@ -1254,13 +1254,13 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->link = elfshname(".dynstr")->shnum;
// sh->info = index of first non-local symbol (number of local symbols)
shsym(sh, lookup(".dynsym", 0));
shsym(sh, linklookup(ctxt, ".dynsym", 0));
sh = elfshname(".dynstr");
sh->type = SHT_STRTAB;
sh->flags = SHF_ALLOC;
sh->addralign = 1;
shsym(sh, lookup(".dynstr", 0));
shsym(sh, linklookup(ctxt, ".dynstr", 0));
if(elfverneed) {
sh = elfshname(".gnu.version");
@ -1269,7 +1269,7 @@ asmbelf(vlong symo)
sh->addralign = 2;
sh->link = elfshname(".dynsym")->shnum;
sh->entsize = 2;
shsym(sh, lookup(".gnu.version", 0));
shsym(sh, linklookup(ctxt, ".gnu.version", 0));
sh = elfshname(".gnu.version_r");
sh->type = SHT_GNU_VERNEED;
@ -1277,7 +1277,7 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->info = elfverneed;
sh->link = elfshname(".dynstr")->shnum;
shsym(sh, lookup(".gnu.version_r", 0));
shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
}
switch(eh->machine) {
@ -1289,7 +1289,7 @@ asmbelf(vlong symo)
sh->addralign = PtrSize;
sh->link = elfshname(".dynsym")->shnum;
sh->info = elfshname(".plt")->shnum;
shsym(sh, lookup(".rela.plt", 0));
shsym(sh, linklookup(ctxt, ".rela.plt", 0));
sh = elfshname(".rela");
sh->type = SHT_RELA;
@ -1297,7 +1297,7 @@ asmbelf(vlong symo)
sh->entsize = ELF64RELASIZE;
sh->addralign = 8;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, lookup(".rela", 0));
shsym(sh, linklookup(ctxt, ".rela", 0));
break;
default:
@ -1306,7 +1306,7 @@ asmbelf(vlong symo)
sh->flags = SHF_ALLOC;
sh->entsize = ELF32RELSIZE;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, lookup(".rel.plt", 0));
shsym(sh, linklookup(ctxt, ".rel.plt", 0));
sh = elfshname(".rel");
sh->type = SHT_REL;
@ -1314,7 +1314,7 @@ asmbelf(vlong symo)
sh->entsize = ELF32RELSIZE;
sh->addralign = 4;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, lookup(".rel", 0));
shsym(sh, linklookup(ctxt, ".rel", 0));
break;
}
@ -1326,21 +1326,21 @@ asmbelf(vlong symo)
else
sh->entsize = 4;
sh->addralign = 4;
shsym(sh, lookup(".plt", 0));
shsym(sh, linklookup(ctxt, ".plt", 0));
sh = elfshname(".got");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
sh->entsize = PtrSize;
sh->addralign = PtrSize;
shsym(sh, lookup(".got", 0));
shsym(sh, linklookup(ctxt, ".got", 0));
sh = elfshname(".got.plt");
sh->type = SHT_PROGBITS;
sh->flags = SHF_ALLOC+SHF_WRITE;
sh->entsize = PtrSize;
sh->addralign = PtrSize;
shsym(sh, lookup(".got.plt", 0));
shsym(sh, linklookup(ctxt, ".got.plt", 0));
sh = elfshname(".hash");
sh->type = SHT_HASH;
@ -1348,7 +1348,7 @@ asmbelf(vlong symo)
sh->entsize = 4;
sh->addralign = PtrSize;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, lookup(".hash", 0));
shsym(sh, linklookup(ctxt, ".hash", 0));
/* sh and PT_DYNAMIC for .dynamic section */
sh = elfshname(".dynamic");
@ -1357,7 +1357,7 @@ asmbelf(vlong symo)
sh->entsize = 2*PtrSize;
sh->addralign = PtrSize;
sh->link = elfshname(".dynstr")->shnum;
shsym(sh, lookup(".dynamic", 0));
shsym(sh, linklookup(ctxt, ".dynamic", 0));
ph = newElfPhdr();
ph->type = PT_DYNAMIC;
ph->flags = PF_R + PF_W;
@ -1369,11 +1369,11 @@ asmbelf(vlong symo)
// Do not emit PT_TLS for OpenBSD since ld.so(1) does
// not currently support it. This is handled
// appropriately in runtime/cgo.
if(tlsoffset != 0 && HEADTYPE != Hopenbsd) {
if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
ph = newElfPhdr();
ph->type = PT_TLS;
ph->flags = PF_R;
ph->memsz = -tlsoffset;
ph->memsz = -ctxt->tlsoffset;
ph->align = PtrSize;
}
}
@ -1394,7 +1394,7 @@ elfobj:
sh = elfshname(".shstrtab");
sh->type = SHT_STRTAB;
sh->addralign = 1;
shsym(sh, lookup(".shstrtab", 0));
shsym(sh, linklookup(ctxt, ".shstrtab", 0));
eh->shstrndx = sh->shnum;
// put these sections early in the list
@ -1430,7 +1430,7 @@ elfobj:
sh = elfshname(".tbss");
sh->type = SHT_NOBITS;
sh->addralign = PtrSize;
sh->size = -tlsoffset;
sh->size = -ctxt->tlsoffset;
sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
}

View file

@ -858,7 +858,7 @@ struct Elf64_Shdr {
Elf64_Xword entsize; /* Size of each entry in section. */
int shnum; /* section number, not stored on disk */
Sym* secsym; /* section symbol, if needed; not on disk */
LSym* secsym; /* section symbol, if needed; not on disk */
};
/*
@ -968,9 +968,9 @@ ElfPhdr *newElfPhdr(void);
uint32 elfwritehdr(void);
uint32 elfwritephdrs(void);
uint32 elfwriteshdrs(void);
void elfwritedynent(Sym*, int, uint64);
void elfwritedynentsym(Sym*, int, Sym*);
void elfwritedynentsymsize(Sym*, int, Sym*);
void elfwritedynent(LSym*, int, uint64);
void elfwritedynentsym(LSym*, int, LSym*);
void elfwritedynentsymsize(LSym*, int, LSym*);
uint32 elfhash(uchar*);
uint64 startelf(void);
uint64 endelf(void);
@ -994,13 +994,13 @@ ElfShdr* elfshalloc(Section*);
ElfShdr* elfshname(char*);
ElfShdr* elfshreloc(Section*);
void elfsetstring(char*, int);
void elfaddverneed(Sym*);
void elfaddverneed(LSym*);
void elfemitreloc(void);
void shsym(ElfShdr*, Sym*);
void shsym(ElfShdr*, LSym*);
void phsh(ElfPhdr*, ElfShdr*);
void doelf(void);
void elfsetupplt(void);
void dwarfaddshstrings(Sym*);
void dwarfaddshstrings(LSym*);
void dwarfaddelfsectionsyms(void);
void dwarfaddelfheaders(void);
void asmbelf(vlong symo);

View file

@ -228,39 +228,6 @@ loadpkgdata(char *file, char *pkg, char *data, int len)
free(file);
}
// replace all "". with pkg.
char*
expandpkg(char *t0, char *pkg)
{
int n;
char *p;
char *w, *w0, *t;
n = 0;
for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
n++;
if(n == 0)
return estrdup(t0);
// use malloc, not mal, so that caller can free
w0 = malloc(strlen(t0) + strlen(pkg)*n);
if(w0 == nil) {
diag("out of memory");
errorexit();
}
w = w0;
for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
memmove(w, t, p - t);
w += p-t;
strcpy(w, pkg);
w += strlen(pkg);
t = p+2;
}
strcpy(w, t);
return w0;
}
static int
parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
{
@ -413,7 +380,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
char *pend, *next, *p0, *q;
char *f[10], *local, *remote, *lib;
int nf;
Sym *s;
LSym *s;
USED(file);
pend = p + n;
@ -459,7 +426,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
q = strchr(remote, '#');
if(q)
*q++ = '\0';
s = lookup(local, 0);
s = linklookup(ctxt, local, 0);
if(local != f[1])
free(local);
if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
@ -477,7 +444,7 @@ loadcgo(char *file, char *pkg, char *p, int n)
if(nf != 2)
goto err;
local = f[1];
s = lookup(local, 0);
s = linklookup(ctxt, local, 0);
s->type = SHOSTOBJ;
s->size = 0;
continue;
@ -496,9 +463,9 @@ loadcgo(char *file, char *pkg, char *p, int n)
else
remote = local;
local = expandpkg(local, pkg);
s = lookup(local, 0);
s = linklookup(ctxt, local, 0);
if(flag_shared && s == lookup("main", 0))
if(flag_shared && s == linklookup(ctxt, "main", 0))
continue;
// export overrides import, for openbsd/cgo.
@ -562,11 +529,11 @@ err:
nerrors++;
}
static Sym *markq;
static Sym *emarkq;
static LSym *markq;
static LSym *emarkq;
static void
mark1(Sym *s, Sym *parent)
mark1(LSym *s, LSym *parent)
{
if(s == S || s->reachable)
return;
@ -582,7 +549,7 @@ mark1(Sym *s, Sym *parent)
}
void
mark(Sym *s)
mark(LSym *s)
{
mark1(s, nil);
}
@ -592,7 +559,7 @@ markflood(void)
{
Auto *a;
Prog *p;
Sym *s;
LSym *s;
int i;
for(s=markq; s!=S; s=s->queue) {
@ -649,7 +616,7 @@ isz(Auto *a)
}
static void
addz(Sym *s, Auto *z)
addz(LSym *s, Auto *z)
{
Auto *a, *last;
@ -674,16 +641,16 @@ void
deadcode(void)
{
int i;
Sym *s, *last, *p;
LSym *s, *last, *p;
Auto *z;
Fmt fmt;
if(debug['v'])
Bprint(&bso, "%5.2f deadcode\n", cputime());
mark(lookup(INITENTRY, 0));
mark(linklookup(ctxt, INITENTRY, 0));
for(i=0; i<nelem(markextra); i++)
mark(lookup(markextra[i], 0));
mark(linklookup(ctxt, markextra[i], 0));
for(i=0; i<ndynexp; i++)
mark(dynexp[i]);
@ -691,7 +658,7 @@ deadcode(void)
markflood();
// keep each beginning with 'typelink.' if the symbol it points at is being kept.
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.typelink.", 12) == 0)
s->reachable = s->nr==1 && s->r[0].sym->reachable;
}
@ -699,14 +666,14 @@ deadcode(void)
// remove dead text but keep file information (z symbols).
last = nil;
z = nil;
for(s = textp; s != nil; s = s->next) {
for(s = ctxt->textp; s != nil; s = s->next) {
if(!s->reachable) {
if(isz(s->autom))
z = s->autom;
continue;
}
if(last == nil)
textp = s;
ctxt->textp = s;
else
last->next = s;
last = s;
@ -717,11 +684,11 @@ deadcode(void)
}
}
if(last == nil)
textp = nil;
ctxt->textp = nil;
else
last->next = nil;
for(s = allsym; s != S; s = s->allsym)
for(s = ctxt->allsym; s != S; s = s->allsym)
if(strncmp(s->name, "go.weak.", 8) == 0) {
s->special = 1; // do not lay out in data segment
s->reachable = 1;
@ -730,7 +697,7 @@ deadcode(void)
// record field tracking references
fmtstrinit(&fmt);
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.track.", 9) == 0) {
s->special = 1; // do not lay out in data segment
s->hide = 1;
@ -746,7 +713,7 @@ deadcode(void)
}
if(tracksym == nil)
return;
s = lookup(tracksym, 0);
s = linklookup(ctxt, tracksym, 0);
if(!s->reachable)
return;
addstrdata(tracksym, fmtstrflush(&fmt));
@ -755,13 +722,13 @@ deadcode(void)
void
doweak(void)
{
Sym *s, *t;
LSym *s, *t;
// resolve weak references only if
// target symbol will be in binary anyway.
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(strncmp(s->name, "go.weak.", 8) == 0) {
t = rlookup(s->name+8, s->version);
t = linkrlookup(ctxt, s->name+8, s->version);
if(t && t->type != 0 && t->reachable) {
s->value = t->value;
s->type = t->type;
@ -784,7 +751,7 @@ addexport(void)
return;
for(i=0; i<ndynexp; i++)
adddynsym(dynexp[i]);
adddynsym(ctxt, dynexp[i]);
}
/* %Z from gc, for quoting import paths */

View file

@ -258,7 +258,7 @@ struct ElfSect
uint64 align;
uint64 entsize;
uchar *base;
Sym *sym;
LSym *sym;
};
struct ElfObj
@ -301,7 +301,7 @@ struct ElfSym
uchar type;
uchar other;
uint16 shndx;
Sym* sym;
LSym* sym;
};
uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
@ -312,7 +312,7 @@ static int readsym(ElfObj*, int i, ElfSym*, int);
static int reltype(char*, int, uchar*);
int
valuecmp(Sym *a, Sym *b)
valuecmp(LSym *a, LSym *b)
{
if(a->value < b->value)
return -1;
@ -336,15 +336,15 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
ElfSym sym;
Endian *e;
Reloc *r, *rp;
Sym *s;
Sym **symbols;
LSym *s;
LSym **symbols;
symbols = nil;
if(debug['v'])
Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
version++;
ctxt->version++;
base = Boffset(f);
if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
@ -529,7 +529,7 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
s = lookup(name, version);
s = linklookup(ctxt, name, ctxt->version);
free(name);
switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
default:
@ -609,14 +609,14 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
} else {
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
p = prg();
p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
p->textflag = 7;
ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
p->pc = pc++;
p->pc = ctxt->pc++;
s->text = p;
}
}
@ -629,16 +629,16 @@ ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
if(etextp)
etextp->next = s;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
textp = s;
etextp = s;
ctxt->textp = s;
ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
etextp->next = s;
etextp = s;
ctxt->etextp->next = s;
ctxt->etextp = s;
}
}
}
@ -761,7 +761,7 @@ map(ElfObj *obj, ElfSect *sect)
static int
readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
{
Sym *s;
LSym *s;
if(i >= obj->nsymtab || i < 0) {
werrstr("invalid elf symbol index");
@ -808,7 +808,7 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
switch(sym->bind) {
case ElfSymBindGlobal:
if(needSym) {
s = lookup(sym->name, 0);
s = linklookup(ctxt, sym->name, 0);
// for global scoped hidden symbols we should insert it into
// symbol hash table, but mark them as hidden.
// __i686.get_pc_thunk.bx is allowed to be duplicated, to
@ -828,13 +828,13 @@ readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
// local names and hidden visiblity global names are unique
// and should only reference by its index, not name, so we
// don't bother to add them into hash table
s = newsym(sym->name, version);
s = linknewsym(ctxt, sym->name, ctxt->version);
s->type |= SHIDDEN;
}
break;
case ElfSymBindWeak:
if(needSym) {
s = newsym(sym->name, 0);
s = linknewsym(ctxt, sym->name, 0);
if(sym->other == 2)
s->type |= SHIDDEN;
}

View file

@ -102,7 +102,7 @@ struct MachoSect
uint32 flags;
uint32 res1;
uint32 res2;
Sym *sym;
LSym *sym;
MachoRel *rel;
};
@ -138,7 +138,7 @@ struct MachoSym
uint16 desc;
char kind;
uint64 value;
Sym *sym;
LSym *sym;
};
struct MachoDysymtab
@ -432,7 +432,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
int64 base;
MachoSect *sect;
MachoRel *rel;
Sym *s, *s1, *outer;
LSym *s, *s1, *outer;
MachoCmd *c;
MachoSymtab *symtab;
MachoDysymtab *dsymtab;
@ -440,7 +440,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
Reloc *r, *rp;
char *name;
version++;
ctxt->version++;
base = Boffset(f);
if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
goto bad;
@ -566,7 +566,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if(strcmp(sect->name, "__eh_frame") == 0)
continue;
name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
s = lookup(name, version);
s = linklookup(ctxt, name, ctxt->version);
if(s->type != 0) {
werrstr("duplicate %s/%s", sect->segname, sect->name);
goto bad;
@ -609,8 +609,8 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
name++;
v = 0;
if(!(sym->type&N_EXT))
v = version;
s = lookup(name, v);
v = ctxt->version;
s = linklookup(ctxt, name, v);
if(!(sym->type&N_EXT))
s->dupok = 1;
sym->sym = s;
@ -647,14 +647,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
// TODO: this is too 6l-specific ?
p = prg();
p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
p->textflag = 7;
ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
p->pc = pc++;
p->pc = ctxt->pc++;
s->text = p;
}
sym->sym = s;
@ -667,7 +667,7 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
if((s = sect->sym) == S)
continue;
if(s->sub) {
s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
// assign sizes, now that we know symbols in sorted order.
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
@ -678,14 +678,14 @@ ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
}
}
if(s->type == STEXT) {
if(etextp)
etextp->next = s;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
textp = s;
etextp = s;
ctxt->textp = s;
ctxt->etextp = s;
for(s1 = s->sub; s1 != S; s1 = s1->sub) {
etextp->next = s1;
etextp = s1;
ctxt->etextp->next = s1;
ctxt->etextp = s1;
}
}
}

View file

@ -102,14 +102,14 @@ struct PeSym {
uint16 type;
uint8 sclass;
uint8 aux;
Sym* sym;
LSym* sym;
};
struct PeSect {
char* name;
uchar* base;
uint64 size;
Sym* sym;
LSym* sym;
IMAGE_SECTION_HEADER sh;
};
@ -141,7 +141,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
PeSect *sect, *rsect;
IMAGE_SECTION_HEADER sh;
uchar symbuf[18];
Sym *s;
LSym *s;
Reloc *r, *rp;
PeSym *sym;
@ -150,7 +150,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
sect = nil;
version++;
ctxt->version++;
base = Boffset(f);
obj = mal(sizeof *obj);
@ -222,7 +222,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
name = smprint("%s(%s)", pkg, sect->name);
s = lookup(name, version);
s = linklookup(ctxt, name, ctxt->version);
free(name);
switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
@ -372,14 +372,14 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
diag("%s: duplicate definition of %s", pn, s->name);
// build a TEXT instruction with a unique pc
// just to make the rest of the linker happy.
p = prg();
p = ctxt->arch->prg();
p->as = ATEXT;
p->from.type = D_EXTERN;
p->from.sym = s;
p->textflag = 7;
ctxt->arch->settextflag(p, 7);
p->to.type = D_CONST;
p->link = nil;
p->pc = pc++;
p->pc = ctxt->pc++;
s->text = p;
}
}
@ -391,16 +391,16 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
if(s == S)
continue;
if(s->sub)
s->sub = listsort(s->sub, valuecmp, offsetof(Sym, sub));
s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
if(s->type == STEXT) {
if(etextp)
etextp->next = s;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
textp = s;
etextp = s;
ctxt->textp = s;
ctxt->etextp = s;
for(s = s->sub; s != S; s = s->sub) {
etextp->next = s;
etextp = s;
ctxt->etextp->next = s;
ctxt->etextp = s;
}
}
}
@ -430,7 +430,7 @@ map(PeObj *obj, PeSect *sect)
static int
readsym(PeObj *obj, int i, PeSym **y)
{
Sym *s;
LSym *s;
PeSym *sym;
char *name, *p;
@ -464,12 +464,12 @@ readsym(PeObj *obj, int i, PeSym **y)
case IMAGE_SYM_DTYPE_NULL:
switch(sym->sclass) {
case IMAGE_SYM_CLASS_EXTERNAL: //global
s = lookup(name, 0);
s = linklookup(ctxt, name, 0);
break;
case IMAGE_SYM_CLASS_NULL:
case IMAGE_SYM_CLASS_STATIC:
case IMAGE_SYM_CLASS_LABEL:
s = lookup(name, version);
s = linklookup(ctxt, name, ctxt->version);
s->dupok = 1;
break;
default:

File diff suppressed because it is too large Load diff

View file

@ -28,68 +28,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
enum
{
Sxxx,
/* order here is order in output file */
/* readonly, executable */
STEXT,
SELFRXSECT,
/* readonly, non-executable */
STYPE,
SSTRING,
SGOSTRING,
SGOFUNC,
SRODATA,
SFUNCTAB,
STYPELINK,
SSYMTAB, // TODO: move to unmapped section
SPCLNTAB,
SELFROSECT,
/* writable, non-executable */
SMACHOPLT,
SELFSECT,
SMACHO, /* Mach-O __nl_symbol_ptr */
SMACHOGOT,
SNOPTRDATA,
SINITARR,
SDATA,
SWINDOWS,
SBSS,
SNOPTRBSS,
STLSBSS,
/* not mapped */
SXREF,
SMACHOSYMSTR,
SMACHOSYMTAB,
SMACHOINDIRECTPLT,
SMACHOINDIRECTGOT,
SFILE,
SFILEPATH,
SCONST,
SDYNIMPORT,
SHOSTOBJ,
SSUB = 1<<8, /* sub-symbol, linked from parent via ->sub list */
SMASK = SSUB - 1,
SHIDDEN = 1<<9, // hidden or local symbol
NHASH = 100003,
};
typedef struct Library Library;
struct Library
{
char *objref; // object where we found the reference
char *srcref; // src file where we found the reference
char *file; // object file
char *pkg; // import path
};
// Terrible but standard terminology.
// A segment describes a block of file to load into memory.
// A section further describes the pieces of that block for
@ -125,36 +63,14 @@ struct Section
uvlong rellen;
};
typedef struct Hist Hist;
#pragma incomplete struct Hist
extern char symname[];
extern char **libdir;
extern int nlibdir;
extern int version;
EXTERN char* INITENTRY;
EXTERN char* thestring;
EXTERN Library* library;
EXTERN int libraryp;
EXTERN int nlibrary;
EXTERN Sym* hash[NHASH];
EXTERN Sym* allsym;
EXTERN Sym* histfrog[MAXHIST];
EXTERN uchar fnuxi8[8];
EXTERN uchar fnuxi4[4];
EXTERN int histfrogp;
EXTERN int histgen;
EXTERN uchar inuxi1[1];
EXTERN uchar inuxi2[2];
EXTERN uchar inuxi4[4];
EXTERN uchar inuxi8[8];
extern char* thestring;
extern LinkArch* thelinkarch;
EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
EXTERN Sym** dynexp;
EXTERN LSym** dynexp;
EXTERN int nldflag;
EXTERN char** ldflag;
EXTERN int havedynamic;
@ -169,16 +85,20 @@ EXTERN char* tmpdir;
EXTERN char* extld;
EXTERN char* extldflags;
EXTERN int debug_s; // backup old value of debug['s']
EXTERN Link* ctxt;
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
EXTERN int32 INITRND;
EXTERN int64 INITTEXT;
EXTERN int64 INITDAT;
EXTERN char* INITENTRY; /* entry point */
EXTERN char* noname;
EXTERN char* paramspace;
EXTERN int nerrors;
enum
{
LinkAuto = 0,
LinkInternal,
LinkExternal,
};
EXTERN int linkmode;
// for dynexport field of Sym
// for dynexport field of LSym
enum
{
CgoExportDynamic = 1<<0,
@ -190,119 +110,6 @@ EXTERN Segment segrodata;
EXTERN Segment segdata;
EXTERN Segment segdwarf;
void setlinkmode(char*);
void addlib(char *src, char *obj);
void addlibpath(char *srcref, char *objref, char *file, char *pkg);
Section* addsection(Segment*, char*, int);
void copyhistfrog(char *buf, int nbuf);
void addhist(int32 line, int type);
void savehist(int32 line, int32 off);
Hist* gethist(void);
void getline(Hist*, int32 line, int32 *f, int32 *l);
void asmlc(void);
void histtoauto(void);
void collapsefrog(Sym *s);
Sym* newsym(char *symb, int v);
Sym* lookup(char *symb, int v);
Sym* rlookup(char *symb, int v);
void nuxiinit(void);
int find1(int32 l, int c);
int find2(int32 l, int c);
int32 ieeedtof(Ieee *e);
double ieeedtod(Ieee *e);
void undefsym(Sym *s);
void zerosig(char *sp);
void readundefs(char *f, int t);
void loadlib(void);
void errorexit(void);
void mangle(char*);
void objfile(char *file, char *pkg);
void libinit(void);
void pclntab(void);
void symtab(void);
void Lflag(char *arg);
void usage(void);
void adddynrel(Sym*, Reloc*);
void adddynrela(Sym*, Sym*, Reloc*);
void ldobj1(Biobuf *f, char*, int64 len, char *pn);
void ldobj(Biobuf*, char*, int64, char*, char*, int);
void ldelf(Biobuf*, char*, int64, char*);
void ldmacho(Biobuf*, char*, int64, char*);
void ldpe(Biobuf*, char*, int64, char*);
void ldpkg(Biobuf*, char*, int64, char*, int);
void mark(Sym *s);
void mkfwd(void);
char* expandpkg(char*, char*);
void deadcode(void);
Reloc* addrel(Sym*);
void codeblk(int32, int32);
void datblk(int32, int32);
void reloc(void);
void relocsym(Sym*);
void savedata(Sym*, Prog*, char*);
void symgrow(Sym*, int32);
void addstrdata(char*, char*);
vlong addstring(Sym*, char*);
vlong adduint8(Sym*, uint8);
vlong adduint16(Sym*, uint16);
vlong adduint32(Sym*, uint32);
vlong adduint64(Sym*, uint64);
vlong adduintxx(Sym*, uint64, int);
vlong addaddr(Sym*, Sym*);
vlong addaddrplus(Sym*, Sym*, vlong);
vlong addpcrelplus(Sym*, Sym*, vlong);
vlong addsize(Sym*, Sym*);
vlong setaddrplus(Sym*, vlong, Sym*, vlong);
vlong setaddr(Sym*, vlong, Sym*);
vlong setuint8(Sym*, vlong, uint8);
vlong setuint16(Sym*, vlong, uint16);
vlong setuint32(Sym*, vlong, uint32);
vlong setuint64(Sym*, vlong, uint64);
vlong setuintxx(Sym*, vlong, uint64, vlong);
void asmsym(void);
void asmelfsym(void);
void asmplan9sym(void);
void putelfsectionsym(Sym*, int);
void putelfsymshndx(vlong, int);
void strnput(char*, int);
void dodata(void);
void dosymtype(void);
void address(void);
void textaddress(void);
void genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*));
vlong datoff(vlong);
void adddynlib(char*);
int archreloc(Reloc*, Sym*, vlong*);
void adddynsym(Sym*);
void addexport(void);
void dostkcheck(void);
void undef(void);
void doweak(void);
void setpersrc(Sym*);
void doversion(void);
void usage(void);
void setinterp(char*);
Sym* listsort(Sym*, int(*cmp)(Sym*, Sym*), int);
int valuecmp(Sym*, Sym*);
void hostobjs(void);
void hostlink(void);
char* estrdup(char*);
void* erealloc(void*, long);
Sym* defgostring(char*);
int pathchar(void);
void* mal(uint32);
void unmal(void*, uint32);
void mywhatsys(void);
int rbyoff(const void*, const void*);
uint16 le16(uchar*);
uint32 le32(uchar*);
uint64 le64(uchar*);
uint16 be16(uchar*);
uint32 be32(uchar*);
uint64 be64(uchar*);
typedef struct Endian Endian;
struct Endian
{
@ -325,28 +132,6 @@ enum {
Pkgdef
};
/* executable header types */
enum {
Hgarbunix = 0, // garbage unix
Hnoheader, // no header
Hunixcoff, // unix coff
Hrisc, // aif for risc os
Hplan9x32, // plan 9 32-bit format
Hplan9x64, // plan 9 64-bit format
Hmsdoscom, // MS-DOS .COM
Hnetbsd, // NetBSD
Hmsdosexe, // fake MS-DOS .EXE
Hixp1200, // IXP1200 (raw)
Helf, // ELF32
Hipaq, // ipaq
Hdarwin, // Apple Mach-O
Hlinux, // Linux ELF
Hfreebsd, // FreeBSD ELF
Hwindows, // MS Windows PE
Hopenbsd, // OpenBSD ELF
Hdragonfly, // DragonFly ELF
};
typedef struct Header Header;
struct Header {
char *name;
@ -356,14 +141,8 @@ struct Header {
EXTERN char* headstring;
extern Header headers[];
int headtype(char*);
char* headstr(int);
void setheadtype(char*);
int Yconv(Fmt*);
#pragma varargck type "O" int
#pragma varargck type "Y" Sym*
#pragma varargck type "Y" LSym*
// buffered output
@ -383,29 +162,115 @@ EXTERN char* cbpmax;
if(--cbc <= 0)\
cflush(); }
void cflush(void);
vlong cpos(void);
void cseek(vlong);
void cwrite(void*, int);
void importcycles(void);
int Zconv(Fmt*);
EXTERN int goarm;
uint8 decodetype_kind(Sym*);
vlong decodetype_size(Sym*);
Sym* decodetype_gc(Sym*);
Sym* decodetype_arrayelem(Sym*);
vlong decodetype_arraylen(Sym*);
Sym* decodetype_ptrelem(Sym*);
Sym* decodetype_mapkey(Sym*);
Sym* decodetype_mapvalue(Sym*);
Sym* decodetype_chanelem(Sym*);
int decodetype_funcdotdotdot(Sym*);
int decodetype_funcincount(Sym*);
int decodetype_funcoutcount(Sym*);
Sym* decodetype_funcintype(Sym*, int);
Sym* decodetype_funcouttype(Sym*, int);
int decodetype_structfieldcount(Sym*);
char* decodetype_structfieldname(Sym*, int);
Sym* decodetype_structfieldtype(Sym*, int);
vlong decodetype_structfieldoffs(Sym*, int);
vlong decodetype_ifacemethodcount(Sym*);
void Lflag(char *arg);
int Yconv(Fmt *fp);
int Zconv(Fmt *fp);
void addexport(void);
void address(void);
Section*addsection(Segment *seg, char *name, int rwx);
void addstrdata(char *name, char *value);
vlong addstring(LSym *s, char *str);
void asmelfsym(void);
void asmplan9sym(void);
uint16 be16(uchar *b);
uint32 be32(uchar *b);
uint64 be64(uchar *b);
void cflush(void);
void codeblk(int32 addr, int32 size);
vlong cpos(void);
void cseek(vlong p);
void cwrite(void *buf, int n);
void datblk(int32 addr, int32 size);
int datcmp(LSym *s1, LSym *s2);
vlong datoff(vlong addr);
void deadcode(void);
LSym* decodetype_arrayelem(LSym *s);
vlong decodetype_arraylen(LSym *s);
LSym* decodetype_chanelem(LSym *s);
int decodetype_funcdotdotdot(LSym *s);
int decodetype_funcincount(LSym *s);
LSym* decodetype_funcintype(LSym *s, int i);
int decodetype_funcoutcount(LSym *s);
LSym* decodetype_funcouttype(LSym *s, int i);
LSym* decodetype_gc(LSym *s);
vlong decodetype_ifacemethodcount(LSym *s);
uint8 decodetype_kind(LSym *s);
LSym* decodetype_mapkey(LSym *s);
LSym* decodetype_mapvalue(LSym *s);
LSym* decodetype_ptrelem(LSym *s);
vlong decodetype_size(LSym *s);
int decodetype_structfieldcount(LSym *s);
char* decodetype_structfieldname(LSym *s, int i);
vlong decodetype_structfieldoffs(LSym *s, int i);
LSym* decodetype_structfieldtype(LSym *s, int i);
void dodata(void);
void dostkcheck(void);
void dostkoff(void);
void dosymtype(void);
void doversion(void);
void doweak(void);
void dynreloc(void);
void dynrelocsym(LSym *s);
vlong entryvalue(void);
void errorexit(void);
void follow(void);
void genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*));
void growdatsize(vlong *datsizep, LSym *s);
char* headstr(int v);
int headtype(char *name);
void hostlink(void);
void hostobjs(void);
int iconv(Fmt *fp);
void importcycles(void);
void ldelf(Biobuf *f, char *pkg, int64 len, char *pn);
void ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file);
void ldmacho(Biobuf *f, char *pkg, int64 len, char *pn);
void ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence);
void ldpe(Biobuf *f, char *pkg, int64 len, char *pn);
void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence);
uint16 le16(uchar *b);
uint32 le32(uchar *b);
uint64 le64(uchar *b);
void libinit(void);
LSym* listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off);
void loadinternal(char *name);
void loadlib(void);
void lputb(int32 l);
void lputl(int32 l);
void* mal(uint32 n);
void mark(LSym *s);
void mywhatsys(void);
struct ar_hdr;
int nextar(Biobuf *bp, int off, struct ar_hdr *a);
void objfile(char *file, char *pkg);
void patch(void);
int pathchar(void);
void pcln(void);
void pclntab(void);
void putelfsectionsym(LSym* s, int shndx);
void putelfsymshndx(vlong sympos, int shndx);
void putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);
int rbyoff(const void *va, const void *vb);
void reloc(void);
void relocsym(LSym *s);
void setheadtype(char *s);
void setinterp(char *s);
void setlinkmode(char *arg);
void span(void);
void strnput(char *s, int n);
vlong symaddr(LSym *s);
void symtab(void);
void textaddress(void);
void undef(void);
void unmal(void *v, uint32 n);
void usage(void);
void vputb(uint64 v);
int valuecmp(LSym *a, LSym *b);
void vputl(uint64 v);
void wputb(ushort w);
void wputl(ushort w);
void xdefine(char *p, int t, vlong v);
void zerosig(char *sp);
void archinit(void);

View file

@ -25,7 +25,7 @@ enum
};
static int nkind[NumSymKind];
static Sym** sortsym;
static LSym** sortsym;
static int nsortsym;
// Amount of space left for adding load commands
@ -232,37 +232,37 @@ machowrite(void)
void
domacho(void)
{
Sym *s;
LSym *s;
if(debug['d'])
return;
// empirically, string table must begin with " \x00".
s = lookup(".machosymstr", 0);
s = linklookup(ctxt, ".machosymstr", 0);
s->type = SMACHOSYMSTR;
s->reachable = 1;
adduint8(s, ' ');
adduint8(s, '\0');
adduint8(ctxt, s, ' ');
adduint8(ctxt, s, '\0');
s = lookup(".machosymtab", 0);
s = linklookup(ctxt, ".machosymtab", 0);
s->type = SMACHOSYMTAB;
s->reachable = 1;
if(linkmode != LinkExternal) {
s = lookup(".plt", 0); // will be __symbol_stub
s = linklookup(ctxt, ".plt", 0); // will be __symbol_stub
s->type = SMACHOPLT;
s->reachable = 1;
s = lookup(".got", 0); // will be __nl_symbol_ptr
s = linklookup(ctxt, ".got", 0); // will be __nl_symbol_ptr
s->type = SMACHOGOT;
s->reachable = 1;
s->align = 4;
s = lookup(".linkedit.plt", 0); // indirect table for .plt
s = linklookup(ctxt, ".linkedit.plt", 0); // indirect table for .plt
s->type = SMACHOINDIRECTPLT;
s->reachable = 1;
s = lookup(".linkedit.got", 0); // indirect table for .got
s = linklookup(ctxt, ".linkedit.got", 0); // indirect table for .got
s->type = SMACHOINDIRECTGOT;
s->reachable = 1;
}
@ -334,7 +334,7 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname)
if(strcmp(sect->name, ".got") == 0) {
msect->name = "__nl_symbol_ptr";
msect->flag = 6; /* section with nonlazy symbol pointers */
msect->res1 = lookup(".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4; /* offset into indirect symbol table */
}
}
@ -432,13 +432,13 @@ asmbmacho(void)
}
if(!debug['d']) {
Sym *s1, *s2, *s3, *s4;
LSym *s1, *s2, *s3, *s4;
// must match domacholink below
s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
s4 = lookup(".machosymstr", 0);
s1 = linklookup(ctxt, ".machosymtab", 0);
s2 = linklookup(ctxt, ".linkedit.plt", 0);
s3 = linklookup(ctxt, ".linkedit.got", 0);
s4 = linklookup(ctxt, ".machosymstr", 0);
if(linkmode != LinkExternal) {
ms = newMachoSeg("__LINKEDIT", 0);
@ -484,7 +484,7 @@ asmbmacho(void)
}
static int
symkind(Sym *s)
symkind(LSym *s)
{
if(s->type == SDYNIMPORT)
return SymKindUndef;
@ -494,7 +494,7 @@ symkind(Sym *s)
}
static void
addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotype)
addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
{
USED(name);
USED(addr);
@ -524,11 +524,11 @@ addsym(Sym *s, char *name, int type, vlong addr, vlong size, int ver, Sym *gotyp
static int
scmp(const void *p1, const void *p2)
{
Sym *s1, *s2;
LSym *s1, *s2;
int k1, k2;
s1 = *(Sym**)p1;
s2 = *(Sym**)p2;
s1 = *(LSym**)p1;
s2 = *(LSym**)p2;
k1 = symkind(s1);
k2 = symkind(s2);
@ -539,12 +539,12 @@ scmp(const void *p1, const void *p2)
}
static void
machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
{
Sym *s;
LSym *s;
genasmsym(put);
for(s=allsym; s; s=s->allsym)
for(s=ctxt->allsym; s; s=s->allsym)
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
if(s->reachable)
put(s, nil, 'D', 0, 0, 0, nil);
@ -573,39 +573,39 @@ static void
machosymtab(void)
{
int i;
Sym *symtab, *symstr, *s, *o;
LSym *symtab, *symstr, *s, *o;
symtab = lookup(".machosymtab", 0);
symstr = lookup(".machosymstr", 0);
symtab = linklookup(ctxt, ".machosymtab", 0);
symstr = linklookup(ctxt, ".machosymstr", 0);
for(i=0; i<nsortsym; i++) {
s = sortsym[i];
adduint32(symtab, symstr->size);
adduint32(ctxt, symtab, symstr->size);
// Only add _ to C symbols. Go symbols have dot in the name.
if(strstr(s->extname, ".") == nil)
adduint8(symstr, '_');
adduint8(ctxt, symstr, '_');
addstring(symstr, s->extname);
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
adduint8(symtab, 0x01); // type N_EXT, external symbol
adduint8(symtab, 0); // no section
adduint16(symtab, 0); // desc
adduintxx(symtab, 0, PtrSize); // no value
adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
adduint8(ctxt, symtab, 0); // no section
adduint16(ctxt, symtab, 0); // desc
adduintxx(ctxt, symtab, 0, PtrSize); // no value
} else {
if(s->cgoexport)
adduint8(symtab, 0x0f);
adduint8(ctxt, symtab, 0x0f);
else
adduint8(symtab, 0x0e);
adduint8(ctxt, symtab, 0x0e);
o = s;
while(o->outer != nil)
o = o->outer;
if(o->sect == nil) {
diag("missing section for %s", s->name);
adduint8(symtab, 0);
adduint8(ctxt, symtab, 0);
} else
adduint8(symtab, o->sect->extnum);
adduint16(symtab, 0); // desc
adduintxx(symtab, symaddr(s), PtrSize);
adduint8(ctxt, symtab, o->sect->extnum);
adduint16(ctxt, symtab, 0); // desc
adduintxx(ctxt, symtab, symaddr(s), PtrSize);
}
}
}
@ -615,7 +615,7 @@ machodysymtab(void)
{
int n;
MachoLoad *ml;
Sym *s1, *s2, *s3;
LSym *s1, *s2, *s3;
ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */
@ -639,9 +639,9 @@ machodysymtab(void)
ml->data[11] = 0; /* nextrefsyms */
// must match domacholink below
s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
s1 = linklookup(ctxt, ".machosymtab", 0);
s2 = linklookup(ctxt, ".linkedit.plt", 0);
s3 = linklookup(ctxt, ".linkedit.got", 0);
ml->data[12] = linkoff + s1->size; /* indirectsymoff */
ml->data[13] = (s2->size + s3->size) / 4; /* nindirectsyms */
@ -655,15 +655,15 @@ vlong
domacholink(void)
{
int size;
Sym *s1, *s2, *s3, *s4;
LSym *s1, *s2, *s3, *s4;
machosymtab();
// write data that will be linkedit section
s1 = lookup(".machosymtab", 0);
s2 = lookup(".linkedit.plt", 0);
s3 = lookup(".linkedit.got", 0);
s4 = lookup(".machosymstr", 0);
s1 = linklookup(ctxt, ".machosymtab", 0);
s2 = linklookup(ctxt, ".linkedit.plt", 0);
s3 = linklookup(ctxt, ".linkedit.got", 0);
s4 = linklookup(ctxt, ".machosymstr", 0);
// Force the linkedit section to end on a 16-byte
// boundary. This allows pure (non-cgo) Go binaries
@ -683,7 +683,7 @@ domacholink(void)
// any alignment padding itself, working around the
// issue.
while(s4->size%16)
adduint8(s4, 0);
adduint8(ctxt, s4, 0);
size = s1->size + s2->size + s3->size + s4->size;
@ -702,9 +702,9 @@ domacholink(void)
void
machorelocsect(Section *sect, Sym *first)
machorelocsect(Section *sect, LSym *first)
{
Sym *sym;
LSym *sym;
int32 eaddr;
Reloc *r;
@ -726,7 +726,7 @@ machorelocsect(Section *sect, Sym *first)
continue;
if(sym->value >= eaddr)
break;
cursym = sym;
ctxt->cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
@ -747,7 +747,7 @@ machoemitreloc(void)
while(cpos()&7)
cput(0);
machorelocsect(segtext.sect, textp);
machorelocsect(segtext.sect, ctxt->textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
machorelocsect(sect, datap);
for(sect=segdata.sect; sect!=nil; sect=sect->next)

104
src/cmd/ld/pass.c Normal file
View file

@ -0,0 +1,104 @@
// Inferno utils/6l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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"
#include "../../pkg/runtime/stack.h"
void
follow(void)
{
LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f follow\n", cputime());
Bflush(&bso);
for(s = ctxt->textp; s != nil; s = s->next)
ctxt->arch->follow(ctxt, s);
}
void
patch(void)
{
LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f mkfwd\n", cputime());
Bflush(&bso);
for(s = ctxt->textp; s != nil; s = s->next)
mkfwd(s);
if(debug['v'])
Bprint(&bso, "%5.2f patch\n", cputime());
Bflush(&bso);
if(flag_shared) {
s = linklookup(ctxt, "init_array", 0);
s->type = SINITARR;
s->reachable = 1;
s->hide = 1;
addaddr(ctxt, s, linklookup(ctxt, INITENTRY, 0));
}
for(s = ctxt->textp; s != nil; s = s->next)
linkpatch(ctxt, s);
}
void
dostkoff(void)
{
LSym *s;
for(s = ctxt->textp; s != nil; s = s->next)
ctxt->arch->addstacksplit(ctxt, s);
}
void
span(void)
{
LSym *s;
if(debug['v'])
Bprint(&bso, "%5.2f span\n", cputime());
for(s = ctxt->textp; s != nil; s = s->next)
ctxt->arch->assemble(ctxt, s);
}
void
pcln(void)
{
LSym *s;
for(s = ctxt->textp; s != nil; s = s->next)
linkpcln(ctxt, s);
}

258
src/cmd/ld/pcln.c Normal file
View file

@ -0,0 +1,258 @@
// Copyright 2013 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 "lib.h"
#include "../../pkg/runtime/funcdata.h"
static void
addvarint(Pcdata *d, uint32 val)
{
int32 n;
uint32 v;
uchar *p;
n = 0;
for(v = val; v >= 0x80; v >>= 7)
n++;
n++;
if(d->n + n > d->m) {
d->m = (d->n + n)*2;
d->p = erealloc(d->p, d->m);
}
p = d->p + d->n;
for(v = val; v >= 0x80; v >>= 7)
*p++ = v | 0x80;
*p++ = v;
d->n += n;
}
static int32
addpctab(LSym *ftab, int32 off, Pcdata *d)
{
int32 start;
start = ftab->np;
symgrow(ctxt, ftab, start + d->n);
memmove(ftab->p + start, d->p, d->n);
return setuint32(ctxt, ftab, off, start);
}
static int32
ftabaddstring(LSym *ftab, char *s)
{
int32 n, start;
n = strlen(s)+1;
start = ftab->np;
symgrow(ctxt, ftab, start+n+1);
strcpy((char*)ftab->p + start, s);
return start;
}
static uint32
getvarint(uchar **pp)
{
uchar *p;
int shift;
uint32 v;
v = 0;
p = *pp;
for(shift = 0;; shift += 7) {
v |= (*p & 0x7F) << shift;
if(!(*p++ & 0x80))
break;
}
*pp = p;
return v;
}
static void
renumberfiles(LSym **files, int nfiles, Pcdata *d)
{
int i;
LSym *f;
Pcdata out;
uint32 v;
int32 oldval, newval, val, dv;
uchar *p;
// Give files numbers.
for(i=0; i<nfiles; i++) {
f = files[i];
if(f->type != SFILEPATH) {
f->value = ++ctxt->nhistfile;
f->type = SFILEPATH;
f->next = ctxt->filesyms;
ctxt->filesyms = f;
}
}
oldval = -1;
newval = -1;
memset(&out, 0, sizeof out);
p = d->p;
while(p < d->p + d->n) {
// value delta
v = getvarint(&p);
if(v == 0 && p != d->p) {
addvarint(&out, 0);
break;
}
dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
oldval += dv;
if(oldval == -1)
val = -1;
else {
if(oldval < 0 || oldval >= nfiles)
sysfatal("bad pcdata %d", oldval);
val = files[oldval]->value;
}
dv = val - newval;
v = (uint32)(dv<<1) ^ (uint32)(dv>>31);
addvarint(&out, v);
// pc delta
v = getvarint(&p);
addvarint(&out, v);
}
free(d->p);
*d = out;
}
// pclntab initializes the pclntab symbol with
// runtime function and file name information.
void
pclntab(void)
{
int32 i, nfunc, start, funcstart;
LSym *ftab, *s;
int32 off, end;
int64 funcdata_bytes;
Pcln *pcln;
static Pcln zpcln;
funcdata_bytes = 0;
ftab = linklookup(ctxt, "pclntab", 0);
ftab->type = SPCLNTAB;
ftab->reachable = 1;
// See golang.org/s/go12symtab for the format. Briefly:
// 8-byte header
// nfunc [PtrSize bytes]
// function table, alternating PC and offset to func struct [each entry PtrSize bytes]
// end PC [PtrSize bytes]
// offset to file table [4 bytes]
nfunc = 0;
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next)
nfunc++;
symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
setuint32(ctxt, ftab, 0, 0xfffffffb);
setuint8(ctxt, ftab, 6, MINLC);
setuint8(ctxt, ftab, 7, PtrSize);
setuintxx(ctxt, ftab, 8, nfunc, PtrSize);
nfunc = 0;
for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) {
pcln = ctxt->cursym->pcln;
if(pcln == nil)
pcln = &zpcln;
funcstart = ftab->np;
funcstart += -ftab->np & (PtrSize-1);
setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym);
setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
// fixed size of struct, checked below
off = funcstart;
end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize;
if(pcln->nfuncdata > 0 && (end&(PtrSize-1)))
end += 4;
symgrow(ctxt, ftab, end);
// entry uintptr
off = setaddr(ctxt, ftab, off, ctxt->cursym);
// name int32
off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name));
// args int32
// TODO: Move into funcinfo.
if(ctxt->cursym->text == nil)
off = setuint32(ctxt, ftab, off, ArgsSizeUnknown);
else
off = setuint32(ctxt, ftab, off, ctxt->cursym->args);
// frame int32
// TODO: Remove entirely. The pcsp table is more precise.
// This is only used by a fallback case during stack walking
// when a called function doesn't have argument information.
// We need to make sure everything has argument information
// and then remove this.
if(ctxt->cursym->text == nil)
off = setuint32(ctxt, ftab, off, 0);
else
off = setuint32(ctxt, ftab, off, (uint32)ctxt->cursym->text->to.offset+PtrSize);
if(pcln != &zpcln)
renumberfiles(pcln->file, pcln->nfile, &pcln->pcfile);
// pcdata
off = addpctab(ftab, off, &pcln->pcsp);
off = addpctab(ftab, off, &pcln->pcfile);
off = addpctab(ftab, off, &pcln->pcline);
off = setuint32(ctxt, ftab, off, pcln->npcdata);
off = setuint32(ctxt, ftab, off, pcln->nfuncdata);
for(i=0; i<pcln->npcdata; i++)
off = addpctab(ftab, off, &pcln->pcdata[i]);
// funcdata, must be pointer-aligned and we're only int32-aligned.
// Missing funcdata will be 0 (nil pointer).
if(pcln->nfuncdata > 0) {
if(off&(PtrSize-1))
off += 4;
for(i=0; i<pcln->nfuncdata; i++) {
if(pcln->funcdata[i] == nil)
setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize);
else {
// TODO: Dedup.
funcdata_bytes += pcln->funcdata[i]->size;
setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
}
}
off += pcln->nfuncdata*PtrSize;
}
if(off != end) {
diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata);
errorexit();
}
// Final entry of table is just end pc.
if(ctxt->cursym->next == nil)
setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size);
}
// Start file table.
start = ftab->np;
start += -ftab->np & (PtrSize-1);
setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4);
setuint32(ctxt, ftab, start, ctxt->nhistfile);
for(s = ctxt->filesyms; s != S; s = s->next)
setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name));
ftab->size = ftab->np;
if(debug['v'])
Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
}

View file

@ -37,7 +37,7 @@ static char *symlabels[] = {
"symtab", "esymtab", "pclntab", "epclntab"
};
static Sym *rsrcsym;
static LSym *rsrcsym;
static char symnames[256];
static int nextsymoff;
@ -62,7 +62,7 @@ static IMAGE_DATA_DIRECTORY* dd;
typedef struct Imp Imp;
struct Imp {
Sym* s;
LSym* s;
uvlong off;
Imp* next;
};
@ -78,7 +78,7 @@ struct Dll {
static Dll* dr;
static Sym *dexport[1024];
static LSym *dexport[1024];
static int nexport;
static IMAGE_SECTION_HEADER*
@ -191,11 +191,11 @@ initdynimport(void)
{
Imp *m;
Dll *d;
Sym *s, *dynamic;
LSym *s, *dynamic;
dr = nil;
m = nil;
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->type != SDYNIMPORT)
continue;
for(d = dr; d != nil; d = d->next) {
@ -216,7 +216,7 @@ initdynimport(void)
d->ms = m;
}
dynamic = lookup(".windynamic", 0);
dynamic = linklookup(ctxt, ".windynamic", 0);
dynamic->reachable = 1;
dynamic->type = SWINDOWS;
for(d = dr; d != nil; d = d->next) {
@ -241,10 +241,10 @@ addimports(IMAGE_SECTION_HEADER *datsect)
vlong startoff, endoff;
Imp *m;
Dll *d;
Sym* dynamic;
LSym* dynamic;
startoff = cpos();
dynamic = lookup(".windynamic", 0);
dynamic = linklookup(ctxt, ".windynamic", 0);
// skip import descriptor table (will write it later)
n = 0;
@ -322,20 +322,20 @@ addimports(IMAGE_SECTION_HEADER *datsect)
static int
scmp(const void *p1, const void *p2)
{
Sym *s1, *s2;
LSym *s1, *s2;
s1 = *(Sym**)p1;
s2 = *(Sym**)p2;
s1 = *(LSym**)p1;
s2 = *(LSym**)p2;
return strcmp(s1->extname, s2->extname);
}
static void
initdynexport(void)
{
Sym *s;
LSym *s;
nexport = 0;
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
continue;
if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
@ -410,10 +410,10 @@ addexports(void)
void
dope(void)
{
Sym *rel;
LSym *rel;
/* relocation table */
rel = lookup(".rel", 0);
rel = linklookup(ctxt, ".rel", 0);
rel->reachable = 1;
rel->type = SELFROSECT;
@ -459,7 +459,7 @@ addsymtable(void)
{
IMAGE_SECTION_HEADER *h;
int i, size;
Sym *s;
LSym *s;
fh.NumberOfSymbols = sizeof(symlabels)/sizeof(symlabels[0]);
size = nextsymoff + 4 + 18*fh.NumberOfSymbols;
@ -471,7 +471,7 @@ addsymtable(void)
// put COFF symbol table
for (i=0; i<fh.NumberOfSymbols; i++) {
s = rlookup(symlabels[i], 0);
s = linkrlookup(ctxt, symlabels[i], 0);
strnput(s->name, 8);
lputl(datoff(s->value));
wputl(textsect);
@ -488,7 +488,7 @@ addsymtable(void)
}
void
setpersrc(Sym *sym)
setpersrc(LSym *sym)
{
if(rsrcsym != nil)
diag("too many .rsrc sections");
@ -535,14 +535,14 @@ addexcept(IMAGE_SECTION_HEADER *text)
IMAGE_SECTION_HEADER *pdata, *xdata;
vlong startoff;
uvlong n;
Sym *sym;
LSym *sym;
USED(text);
if(thechar != '6')
return;
// write unwind info
sym = lookup("runtime.sigtramp", 0);
sym = linklookup(ctxt, "runtime.sigtramp", 0);
startoff = cpos();
lputl(9); // version=1, flags=UNW_FLAG_EHANDLER, rest 0
lputl(sym->value - PEBASE);

View file

@ -176,4 +176,4 @@ typedef struct {
IMAGE_DATA_DIRECTORY DataDirectory[16];
} PE64_IMAGE_OPTIONAL_HEADER;
void setpersrc(Sym *sym);
void setpersrc(LSym *sym);

223
src/cmd/ld/pobj.c Normal file
View file

@ -0,0 +1,223 @@
// Inferno utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
// Reading object files.
#define EXTERN
#include "l.h"
#include "../ld/lib.h"
#include "../ld/elf.h"
#include "../ld/macho.h"
#include "../ld/dwarf.h"
#include "../ld/pe.h"
#include <ar.h>
char *noname = "<none>";
char* paramspace = "FP";
Header headers[] = {
"darwin", Hdarwin,
"dragonfly", Hdragonfly,
"elf", Helf,
"freebsd", Hfreebsd,
"linux", Hlinux,
"netbsd", Hnetbsd,
"openbsd", Hopenbsd,
"plan9", Hplan9,
"windows", Hwindows,
"windowsgui", Hwindows,
0, 0
};
void
main(int argc, char *argv[])
{
char *p;
ctxt = linknew(thelinkarch);
ctxt->thechar = thechar;
ctxt->thestring = thestring;
ctxt->diag = diag;
ctxt->dwarfaddfrag = dwarfaddfrag;
ctxt->bso = &bso;
Binit(&bso, 1, OWRITE);
listinit();
memset(debug, 0, sizeof(debug));
nerrors = 0;
outfile = nil;
HEADTYPE = -1;
INITTEXT = -1;
INITDAT = -1;
INITRND = -1;
INITENTRY = 0;
linkmode = LinkAuto;
nuxiinit();
if(thechar == '5') {
p = getgoarm();
if(p != nil)
goarm = atoi(p);
else
goarm = 6;
if(goarm == 5)
debug['F'] = 1;
ctxt->goarm = goarm;
}
flagcount("1", "use alternate profiling code", &debug['1']);
if(thechar == '6')
flagcount("8", "assume 64-bit addresses", &debug['8']);
flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
flagint64("D", "addr: data address", &INITDAT);
flagstr("E", "sym: entry symbol", &INITENTRY);
if(thechar == '5')
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']);
if(thechar == '5')
flagcount("M", "disable software div/mod", &debug['M']);
flagcount("O", "print pc-line tables", &debug['O']);
flagcount("Q", "debug byte-register code gen", &debug['Q']);
if(thechar == '5')
flagcount("P", "debug code generation", &debug['P']);
flagint32("R", "rnd: address rounding", &INITRND);
flagcount("S", "check type signatures", &debug['S']);
flagint64("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);
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']);
if(thechar == '5' || thechar == '6')
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);
ctxt->bso = &bso;
ctxt->debugdivmod = debug['M'];
ctxt->debugfloat = debug['F'];
ctxt->debughist = debug['O'];
ctxt->debugpcln = debug['O'];
ctxt->debugread = debug['W'];
ctxt->debugstack = debug['K'];
ctxt->debugvlog = debug['v'];
if(argc != 1)
usage();
if(outfile == nil) {
if(HEADTYPE == Hwindows)
outfile = smprint("%c.out.exe", thechar);
else
outfile = smprint("%c.out", thechar);
}
libinit(); // creates outfile
if(HEADTYPE == -1)
HEADTYPE = headtype(goos);
ctxt->headtype = HEADTYPE;
archinit();
ctxt->linkmode = linkmode;
ctxt->debugfloat = debug['F'];
if(debug['v'])
Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
HEADTYPE, INITTEXT, INITDAT, INITRND);
Bflush(&bso);
cbp = buf.cbuf;
cbc = sizeof(buf.cbuf);
addlibpath(ctxt, "command line", "command line", argv[0], "main");
loadlib();
if(thechar == '5') {
// mark some functions that are only referenced after linker code editing
if(debug['F'])
mark(linkrlookup(ctxt, "_sfloat", 0));
mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
}
deadcode();
patch();
follow();
dostkoff();
paramspace = "SP"; /* (FP) now (SP) on output */
span();
pcln();
doelf();
if(HEADTYPE == Hdarwin)
domacho();
dostkcheck();
if(HEADTYPE == Hwindows)
dope();
addexport();
textaddress();
pclntab();
symtab();
dodata();
address();
doweak();
reloc();
asmb();
undef();
hostlink();
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d symbols\n", ctxt->nsymbol);
Bprint(&bso, "%d sizeof adr\n", sizeof(Addr));
Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
}
Bflush(&bso);
errorexit();
}

View file

@ -86,10 +86,10 @@ static int numelfsym = 1; // 0 is reserved
static int elfbind;
static void
putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int bind, type, off;
Sym *xo;
LSym *xo;
USED(go);
switch(t) {
@ -109,12 +109,12 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
while(xo->outer != nil)
xo = xo->outer;
if(xo->sect == nil) {
cursym = x;
ctxt->cursym = x;
diag("missing section in putelfsym");
return;
}
if(xo->sect->elfsect == nil) {
cursym = x;
ctxt->cursym = x;
diag("missing ELF section in putelfsym");
return;
}
@ -143,7 +143,7 @@ putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
}
void
putelfsectionsym(Sym* s, int shndx)
putelfsectionsym(LSym* s, int shndx)
{
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
s->elfsym = numelfsym++;
@ -170,7 +170,7 @@ putelfsymshndx(vlong sympos, int shndx)
void
asmelfsym(void)
{
Sym *s;
LSym *s;
// the first symbol entry is reserved
putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
@ -181,9 +181,9 @@ asmelfsym(void)
genasmsym(putelfsym);
if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
s = lookup("runtime.tlsgm", 0);
s = linklookup(ctxt, "runtime.tlsgm", 0);
if(s->sect == nil) {
cursym = nil;
ctxt->cursym = nil;
diag("missing section for %s", s->name);
errorexit();
}
@ -195,7 +195,7 @@ asmelfsym(void)
elfglobalsymndx = numelfsym;
genasmsym(putelfsym);
for(s=allsym; s!=S; s=s->allsym) {
for(s=ctxt->allsym; s!=S; s=s->allsym) {
if(s->type != SHOSTOBJ)
continue;
putelfsyment(putelfstr(s->name), 0, 0, (STB_GLOBAL<<4)|STT_NOTYPE, 0, 0);
@ -204,7 +204,7 @@ asmelfsym(void)
}
static void
putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
{
int i, l;
@ -226,7 +226,7 @@ putplan9sym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
case 'Z':
case 'm':
l = 4;
if(HEADTYPE == Hplan9x64 && !debug['8']) {
if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
lputb(addr>>32);
l = 8;
}
@ -263,14 +263,14 @@ asmplan9sym(void)
genasmsym(putplan9sym);
}
static Sym *symt;
static LSym *symt;
static void
scput(int b)
{
uchar *p;
symgrow(symt, symt->size+1);
symgrow(ctxt, symt, symt->size+1);
p = symt->p + symt->size;
*p = b;
symt->size++;
@ -281,7 +281,7 @@ slputb(int32 v)
{
uchar *p;
symgrow(symt, symt->size+4);
symgrow(ctxt, symt, symt->size+4);
p = symt->p + symt->size;
*p++ = v>>24;
*p++ = v>>16;
@ -295,7 +295,7 @@ slputl(int32 v)
{
uchar *p;
symgrow(symt, symt->size+4);
symgrow(ctxt, symt, symt->size+4);
p = symt->p + symt->size;
*p++ = v;
*p++ = v>>8;
@ -355,7 +355,7 @@ vputl(uint64 v)
// Emit symbol table entry.
// The table format is described at the top of ../../pkg/runtime/symtab.c.
void
putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ)
{
int i, f, c;
vlong v1;
@ -457,7 +457,7 @@ putsymb(Sym *s, char *name, int t, vlong v, vlong size, int ver, Sym *typ)
void
symtab(void)
{
Sym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
dosymtype();
@ -482,40 +482,40 @@ symtab(void)
xdefine("esymtab", SRODATA, 0);
// garbage collection symbols
s = lookup("gcdata", 0);
s = linklookup(ctxt, "gcdata", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcdata", SRODATA, 0);
s = lookup("gcbss", 0);
s = linklookup(ctxt, "gcbss", 0);
s->type = SRODATA;
s->size = 0;
s->reachable = 1;
xdefine("egcbss", SRODATA, 0);
// pseudo-symbols to mark locations of type, string, and go string data.
s = lookup("type.*", 0);
s = linklookup(ctxt, "type.*", 0);
s->type = STYPE;
s->size = 0;
s->reachable = 1;
symtype = s;
s = lookup("go.string.*", 0);
s = linklookup(ctxt, "go.string.*", 0);
s->type = SGOSTRING;
s->size = 0;
s->reachable = 1;
symgostring = s;
s = lookup("go.func.*", 0);
s = linklookup(ctxt, "go.func.*", 0);
s->type = SGOFUNC;
s->size = 0;
s->reachable = 1;
symgofunc = s;
symtypelink = lookup("typelink", 0);
symtypelink = linklookup(ctxt, "typelink", 0);
symt = lookup("symtab", 0);
symt = linklookup(ctxt, "symtab", 0);
symt->type = SSYMTAB;
symt->size = 0;
symt->reachable = 1;
@ -524,7 +524,7 @@ symtab(void)
// within a type they sort by size, so the .* symbols
// just defined above will be first.
// hide the specific symbols.
for(s = allsym; s != S; s = s->allsym) {
for(s = ctxt->allsym; s != S; s = s->allsym) {
if(!s->reachable || s->special || s->type != SRODATA)
continue;
if(strncmp(s->name, "type.", 5) == 0) {

5
src/liblink/Makefile Normal file
View file

@ -0,0 +1,5 @@
# Copyright 2013 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.dist

2443
src/liblink/asm5.c Normal file

File diff suppressed because it is too large Load diff

3289
src/liblink/asm6.c Normal file

File diff suppressed because it is too large Load diff

2571
src/liblink/asm8.c Normal file

File diff suppressed because it is too large Load diff

366
src/liblink/data.c Normal file
View file

@ -0,0 +1,366 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
void
mangle(char *file)
{
sysfatal("%s: mangled input file", file);
}
void
symgrow(Link *ctxt, LSym *s, int32 siz)
{
USED(ctxt);
if(s->np >= siz)
return;
if(s->np > s->maxp) {
ctxt->cursym = s;
sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
}
if(s->maxp < siz) {
if(s->maxp == 0)
s->maxp = 8;
while(s->maxp < siz)
s->maxp <<= 1;
s->p = erealloc(s->p, s->maxp);
memset(s->p+s->np, 0, s->maxp-s->np);
}
s->np = siz;
}
void
savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
{
int32 off, siz, i, fl;
float32 flt;
uchar *cast;
vlong o;
Reloc *r;
off = p->from.offset;
siz = ctxt->arch->datasize(p);
if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
mangle(pn);
symgrow(ctxt, s, off+siz);
if(p->to.type == ctxt->arch->D_FCONST) {
switch(siz) {
default:
case 4:
flt = p->to.u.dval;
cast = (uchar*)&flt;
for(i=0; i<4; i++)
s->p[off+i] = cast[fnuxi4[i]];
break;
case 8:
cast = (uchar*)&p->to.u.dval;
for(i=0; i<8; i++)
s->p[off+i] = cast[fnuxi8[i]];
break;
}
} else if(p->to.type == ctxt->arch->D_SCONST) {
for(i=0; i<siz; i++)
s->p[off+i] = p->to.u.sval[i];
} else if(p->to.type == ctxt->arch->D_CONST) {
if(p->to.sym)
goto Addr;
o = p->to.offset;
fl = o;
cast = (uchar*)&fl;
switch(siz) {
default:
ctxt->diag("bad nuxi %d\n%P", siz, p);
break;
case 1:
s->p[off] = cast[inuxi1[0]];
break;
case 2:
for(i=0; i<2; i++)
s->p[off+i] = cast[inuxi2[i]];
break;
case 4:
for(i=0; i<4; i++)
s->p[off+i] = cast[inuxi4[i]];
break;
case 8:
cast = (uchar*)&o;
for(i=0; i<8; i++)
s->p[off+i] = cast[inuxi8[i]];
break;
}
} else if(p->to.type == ctxt->arch->D_ADDR || p->to.type == ctxt->arch->D_SIZE) {
Addr:
r = addrel(s);
r->off = off;
r->siz = siz;
r->sym = p->to.sym;
r->type = p->to.type;
if(r->type != ctxt->arch->D_SIZE)
r->type = ctxt->arch->D_ADDR;
r->add = p->to.offset;
} else {
ctxt->diag("bad data: %P", p);
}
}
Reloc*
addrel(LSym *s)
{
if(s->nr >= s->maxr) {
if(s->maxr == 0)
s->maxr = 4;
else
s->maxr <<= 1;
s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
}
return &s->r[s->nr++];
}
vlong
setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid)
{
int32 i, fl;
vlong o;
uchar *cast;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
if(s->size < off+wid) {
s->size = off+wid;
symgrow(ctxt, s, s->size);
}
fl = v;
cast = (uchar*)&fl;
switch(wid) {
case 1:
s->p[off] = cast[inuxi1[0]];
break;
case 2:
for(i=0; i<2; i++)
s->p[off+i] = cast[inuxi2[i]];
break;
case 4:
for(i=0; i<4; i++)
s->p[off+i] = cast[inuxi4[i]];
break;
case 8:
o = v;
cast = (uchar*)&o;
for(i=0; i<8; i++)
s->p[off+i] = cast[inuxi8[i]];
break;
}
return off+wid;
}
vlong
adduintxx(Link *ctxt, LSym *s, uint64 v, int wid)
{
vlong off;
off = s->size;
setuintxx(ctxt, s, off, v, wid);
return off;
}
vlong
adduint8(Link *ctxt, LSym *s, uint8 v)
{
return adduintxx(ctxt, s, v, 1);
}
vlong
adduint16(Link *ctxt, LSym *s, uint16 v)
{
return adduintxx(ctxt, s, v, 2);
}
vlong
adduint32(Link *ctxt, LSym *s, uint32 v)
{
return adduintxx(ctxt, s, v, 4);
}
vlong
adduint64(Link *ctxt, LSym *s, uint64 v)
{
return adduintxx(ctxt, s, v, 8);
}
vlong
setuint8(Link *ctxt, LSym *s, vlong r, uint8 v)
{
return setuintxx(ctxt, s, r, v, 1);
}
vlong
setuint16(Link *ctxt, LSym *s, vlong r, uint16 v)
{
return setuintxx(ctxt, s, r, v, 2);
}
vlong
setuint32(Link *ctxt, LSym *s, vlong r, uint32 v)
{
return setuintxx(ctxt, s, r, v, 4);
}
vlong
setuint64(Link *ctxt, LSym *s, vlong r, uint64 v)
{
return setuintxx(ctxt, s, r, v, 8);
}
vlong
addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += ctxt->arch->ptrsize;
symgrow(ctxt, s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = ctxt->arch->ptrsize;
r->type = ctxt->arch->D_ADDR;
r->add = add;
return i + r->siz;
}
vlong
addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += 4;
symgrow(ctxt, s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->add = add;
r->type = ctxt->arch->D_PCREL;
r->siz = 4;
return i + r->siz;
}
vlong
addaddr(Link *ctxt, LSym *s, LSym *t)
{
return addaddrplus(ctxt, s, t, 0);
}
vlong
setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add)
{
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
if(off+ctxt->arch->ptrsize > s->size) {
s->size = off + ctxt->arch->ptrsize;
symgrow(ctxt, s, s->size);
}
r = addrel(s);
r->sym = t;
r->off = off;
r->siz = ctxt->arch->ptrsize;
r->type = ctxt->arch->D_ADDR;
r->add = add;
return off + r->siz;
}
vlong
setaddr(Link *ctxt, LSym *s, vlong off, LSym *t)
{
return setaddrplus(ctxt, s, off, t, 0);
}
vlong
addsize(Link *ctxt, LSym *s, LSym *t)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += ctxt->arch->ptrsize;
symgrow(ctxt, s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = ctxt->arch->ptrsize;
r->type = ctxt->arch->D_SIZE;
return i + r->siz;
}
vlong
addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add)
{
vlong i;
Reloc *r;
if(s->type == 0)
s->type = SDATA;
s->reachable = 1;
i = s->size;
s->size += 4;
symgrow(ctxt, s, s->size);
r = addrel(s);
r->sym = t;
r->off = i;
r->siz = 4;
r->type = ctxt->arch->D_ADDR;
r->add = add;
return i + r->siz;
}

74
src/liblink/go.c Normal file
View file

@ -0,0 +1,74 @@
// 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.
// go-specific code shared across loaders (5l, 6l, 8l).
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
// replace all "". with pkg.
char*
expandpkg(char *t0, char *pkg)
{
int n;
char *p;
char *w, *w0, *t;
n = 0;
for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
n++;
if(n == 0)
return estrdup(t0);
w0 = emallocz(strlen(t0) + strlen(pkg)*n);
w = w0;
for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
memmove(w, t, p - t);
w += p-t;
strcpy(w, pkg);
w += strlen(pkg);
t = p+2;
}
strcpy(w, t);
return w0;
}
void*
emallocz(long n)
{
void *p;
p = malloc(n);
if(p == nil)
sysfatal("out of memory");
memset(p, 0, n);
return p;
}
char*
estrdup(char *p)
{
p = strdup(p);
if(p == nil)
sysfatal("out of memory");
return p;
}
void*
erealloc(void *p, long n)
{
p = realloc(p, n);
if(p == nil)
sysfatal("out of memory");
return p;
}
void
double2ieee(uint64 *ieee, float64 f)
{
memmove(ieee, &f, 8);
}

572
src/liblink/ld.c Normal file
View file

@ -0,0 +1,572 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
void
copyhistfrog(Link *ctxt, char *buf, int nbuf)
{
char *p, *ep;
int i;
p = buf;
ep = buf + nbuf;
for(i=0; i<ctxt->histfrogp; i++) {
p = seprint(p, ep, "%s", ctxt->histfrog[i]->name+1);
if(i+1<ctxt->histfrogp && (p == buf || p[-1] != '/'))
p = seprint(p, ep, "/");
}
}
void
addhist(Link *ctxt, int32 line, int type)
{
Auto *u;
LSym *s;
int i, j, k;
u = emallocz(sizeof(Auto));
s = emallocz(sizeof(LSym));
s->name = emallocz(2*(ctxt->histfrogp+1) + 1);
u->asym = s;
u->type = type;
u->aoffset = line;
u->link = ctxt->curhist;
ctxt->curhist = u;
s->name[0] = 0;
j = 1;
for(i=0; i<ctxt->histfrogp; i++) {
k = ctxt->histfrog[i]->value;
s->name[j+0] = k>>8;
s->name[j+1] = k;
j += 2;
}
s->name[j] = 0;
s->name[j+1] = 0;
}
void
histtoauto(Link *ctxt)
{
Auto *l;
while(l = ctxt->curhist) {
ctxt->curhist = l->link;
l->link = ctxt->curauto;
ctxt->curauto = l;
}
}
void
collapsefrog(Link *ctxt, LSym *s)
{
int i;
/*
* bad encoding of path components only allows
* MAXHIST components. if there is an overflow,
* first try to collapse xxx/..
*/
for(i=1; i<ctxt->histfrogp; i++)
if(strcmp(ctxt->histfrog[i]->name+1, "..") == 0) {
memmove(ctxt->histfrog+i-1, ctxt->histfrog+i+1,
(ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
ctxt->histfrogp--;
goto out;
}
/*
* next try to collapse .
*/
for(i=0; i<ctxt->histfrogp; i++)
if(strcmp(ctxt->histfrog[i]->name+1, ".") == 0) {
memmove(ctxt->histfrog+i, ctxt->histfrog+i+1,
(ctxt->histfrogp-i-1)*sizeof(ctxt->histfrog[0]));
goto out;
}
/*
* last chance, just truncate from front
*/
memmove(ctxt->histfrog+0, ctxt->histfrog+1,
(ctxt->histfrogp-1)*sizeof(ctxt->histfrog[0]));
out:
ctxt->histfrog[ctxt->histfrogp-1] = s;
}
// Saved history stacks encountered while reading archives.
// Keeping them allows us to answer virtual lineno -> file:line
// queries.
//
// The history stack is a complex data structure, described best at the
// bottom of http://plan9.bell-labs.com/magic/man2html/6/a.out.
// One of the key benefits of interpreting it here is that the runtime
// does not have to. Perhaps some day the compilers could generate
// a simpler linker input too.
// savehist processes a single line, off history directive
// found in the input object file.
void
savehist(Link *ctxt, int32 line, int32 off)
{
char tmp[1024];
LSym *file;
Hist2 *h;
// NOTE(rsc): We used to do the copyctxt->histfrog first and this
// condition was if(tmp[0] != '\0') to check for an empty string,
// implying that ctxt->histfrogp == 0, implying that this is a history pop.
// However, on Windows in the misc/cgo test, the linker is
// presented with an ANAME corresponding to an empty string,
// that ANAME ends up being the only ctxt->histfrog, and thus we have
// a situation where ctxt->histfrogp > 0 (not a pop) but the path we find
// is the empty string. Really that shouldn't happen, but it doesn't
// seem to be bothering anyone yet, and it's easier to fix the condition
// to test ctxt->histfrogp than to track down where that empty string is
// coming from. Probably it is coming from go tool pack's P command.
if(ctxt->histfrogp > 0) {
tmp[0] = '\0';
copyhistfrog(ctxt, tmp, sizeof tmp);
file = linklookup(ctxt, tmp, HistVersion);
} else
file = nil;
if(file != nil && line == 1 && off == 0) {
// start of new stack
if(ctxt->histdepth != 0)
sysfatal("history stack phase error: unexpected start of new stack depth=%d file=%s", ctxt->histdepth, tmp);
ctxt->nhist2 = 0;
ctxt->histcopy = nil;
}
if(ctxt->nhist2 >= ctxt->maxhist2) {
if(ctxt->maxhist2 == 0)
ctxt->maxhist2 = 1;
ctxt->maxhist2 *= 2;
ctxt->hist2 = erealloc(ctxt->hist2, ctxt->maxhist2*sizeof ctxt->hist2[0]);
}
h = &ctxt->hist2[ctxt->nhist2++];
h->line = line;
h->off = off;
h->file = file;
if(file != nil) {
if(off == 0)
ctxt->histdepth++;
} else {
if(off != 0)
sysfatal("history stack phase error: bad offset in pop");
ctxt->histdepth--;
}
}
// gethist returns the history stack currently in effect.
// The result is valid indefinitely.
Hist2*
gethist(Link *ctxt)
{
if(ctxt->histcopy == nil) {
if(ctxt->nhist2 == 0)
return nil;
ctxt->histcopy = emallocz((ctxt->nhist2+1)*sizeof ctxt->hist2[0]);
memmove(ctxt->histcopy, ctxt->hist2, ctxt->nhist2*sizeof ctxt->hist2[0]);
ctxt->histcopy[ctxt->nhist2].line = -1;
}
return ctxt->histcopy;
}
typedef struct Hstack Hstack;
struct Hstack
{
Hist2 *h;
int delta;
};
// getline sets *f to the file number and *l to the line number
// of the virtual line number line according to the history stack h.
void
linkgetline(Link *ctxt, Hist2 *h, int32 line, LSym **f, int32 *l)
{
Hstack stk[100];
int nstk, start;
Hist2 *top, *h0;
static Hist2 *lasth;
static int32 laststart, lastend, lastdelta;
static LSym *lastfile;
h0 = h;
*f = 0;
*l = 0;
start = 0;
if(h == nil || line == 0) {
print("%s: getline: h=%p line=%d\n", ctxt->cursym->name, h, line);
return;
}
// Cache span used during last lookup, so that sequential
// translation of line numbers in compiled code is efficient.
if(!ctxt->debughist && lasth == h && laststart <= line && line < lastend) {
*f = lastfile;
*l = line - lastdelta;
return;
}
if(ctxt->debughist)
print("getline %d laststart=%d lastend=%d\n", line, laststart, lastend);
nstk = 0;
for(; h->line != -1; h++) {
if(ctxt->debughist)
print("\t%s %d %d\n", h->file ? h->file->name : "?", h->line, h->off);
if(h->line > line) {
if(nstk == 0)
sysfatal("history stack phase error: empty stack at line %d", (int)line);
top = stk[nstk-1].h;
lasth = h;
lastfile = top->file;
laststart = start;
lastend = h->line;
lastdelta = stk[nstk-1].delta;
*f = lastfile;
*l = line - lastdelta;
if(ctxt->debughist)
print("\tgot %d %d [%d %d %d]\n", *f, *l, laststart, lastend, lastdelta);
return;
}
if(h->file == nil) {
// pop included file
if(nstk == 0)
sysfatal("history stack phase error: stack underflow");
nstk--;
if(nstk > 0)
stk[nstk-1].delta += h->line - stk[nstk].h->line;
start = h->line;
} else if(h->off == 0) {
// push included file
if(nstk >= nelem(stk))
sysfatal("history stack phase error: stack overflow");
start = h->line;
stk[nstk].h = h;
stk[nstk].delta = h->line - 1;
nstk++;
} else {
// #line directive
if(nstk == 0)
sysfatal("history stack phase error: stack underflow");
stk[nstk-1].h = h;
stk[nstk-1].delta = h->line - h->off;
start = h->line;
}
if(ctxt->debughist)
print("\t\tnstk=%d delta=%d\n", nstk, stk[nstk].delta);
}
sysfatal("history stack phase error: cannot find line for %d", line);
nstk = 0;
for(h = h0; h->line != -1; h++) {
print("\t%d %d %s\n", h->line, h->off, h->file ? h->file->name : "");
if(h->file == nil)
nstk--;
else if(h->off == 0)
nstk++;
}
}
void
addlib(Link *ctxt, char *src, char *obj)
{
char name[1024], pname[1024], comp[256], *p;
int i, search;
if(ctxt->histfrogp <= 0)
return;
search = 0;
if(ctxt->histfrog[0]->name[1] == '/') {
sprint(name, "");
i = 1;
} else
if(isalpha((uchar)ctxt->histfrog[0]->name[1]) && ctxt->histfrog[0]->name[2] == ':') {
strcpy(name, ctxt->histfrog[0]->name+1);
i = 1;
} else
if(ctxt->histfrog[0]->name[1] == '.') {
sprint(name, ".");
i = 0;
} else {
sprint(name, "");
i = 0;
search = 1;
}
for(; i<ctxt->histfrogp; i++) {
snprint(comp, sizeof comp, "%s", ctxt->histfrog[i]->name+1);
for(;;) {
p = strstr(comp, "$O");
if(p == 0)
break;
memmove(p+1, p+2, strlen(p+2)+1);
p[0] = ctxt->thechar;
}
for(;;) {
p = strstr(comp, "$M");
if(p == 0)
break;
if(strlen(comp)+strlen(ctxt->thestring)-2+1 >= sizeof comp)
sysfatal("library component too long");
memmove(p+strlen(ctxt->thestring), p+2, strlen(p+2)+1);
memmove(p, ctxt->thestring, strlen(ctxt->thestring));
}
if(strlen(name) + strlen(comp) + 3 >= sizeof(name))
sysfatal("library component too long");
if(i > 0 || !search)
strcat(name, "/");
strcat(name, comp);
}
cleanname(name);
// runtime.a -> runtime
p = nil;
if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
p = name+strlen(name)-2;
*p = '\0';
}
// already loaded?
for(i=0; i<ctxt->libraryp; i++)
if(strcmp(ctxt->library[i].pkg, name) == 0)
return;
// runtime -> runtime.a for search
if(p != nil)
*p = '.';
if(search) {
// try dot, -L "libdir", and then goroot.
for(i=0; i<ctxt->nlibdir; i++) {
snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
if(access(pname, AEXIST) >= 0)
break;
}
}else
strcpy(pname, name);
cleanname(pname);
/* runtime.a -> runtime */
if(p != nil)
*p = '\0';
if(ctxt->debugvlog > 1 && ctxt->bso)
Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
addlibpath(ctxt, src, obj, pname, name);
}
/*
* add library to library list.
* srcref: src file referring to package
* objref: object file referring to package
* file: object file, e.g., /home/rsc/go/pkg/container/vector.a
* pkg: package import path, e.g. container/vector
*/
void
addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg)
{
int i;
Library *l;
for(i=0; i<ctxt->libraryp; i++)
if(strcmp(file, ctxt->library[i].file) == 0)
return;
if(ctxt->debugvlog > 1 && ctxt->bso)
Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
cputime(), srcref, objref, file, pkg);
if(ctxt->libraryp == ctxt->nlibrary){
ctxt->nlibrary = 50 + 2*ctxt->libraryp;
ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary);
}
l = &ctxt->library[ctxt->libraryp++];
l->objref = estrdup(objref);
l->srcref = estrdup(srcref);
l->file = estrdup(file);
l->pkg = estrdup(pkg);
}
int
find1(int32 l, int c)
{
char *p;
int i;
p = (char*)&l;
for(i=0; i<4; i++)
if(*p++ == c)
return i;
return 0;
}
void
nuxiinit(void)
{
int i, c;
for(i=0; i<4; i++) {
c = find1(0x04030201L, i+1);
if(i < 2)
inuxi2[i] = c;
if(i < 1)
inuxi1[i] = c;
inuxi4[i] = c;
if(c == i) {
inuxi8[i] = c;
inuxi8[i+4] = c+4;
} else {
inuxi8[i] = c+4;
inuxi8[i+4] = c;
}
fnuxi4[i] = c;
fnuxi8[i] = c;
fnuxi8[i+4] = c+4;
}
}
uchar fnuxi8[8];
uchar fnuxi4[4];
uchar inuxi1[1];
uchar inuxi2[2];
uchar inuxi4[4];
uchar inuxi8[8];
#define LOG 5
void
mkfwd(LSym *sym)
{
Prog *p;
int i;
int32 dwn[LOG], cnt[LOG];
Prog *lst[LOG];
for(i=0; i<LOG; i++) {
if(i == 0)
cnt[i] = 1;
else
cnt[i] = LOG * cnt[i-1];
dwn[i] = 1;
lst[i] = nil;
}
i = 0;
for(p = sym->text; p != nil && p->link != nil; p = p->link) {
i--;
if(i < 0)
i = LOG-1;
p->forwd = nil;
dwn[i]--;
if(dwn[i] <= 0) {
dwn[i] = cnt[i];
if(lst[i] != nil)
lst[i]->forwd = p;
lst[i] = p;
}
}
}
Prog*
copyp(Link *ctxt, Prog *q)
{
Prog *p;
p = ctxt->arch->prg();
*p = *q;
return p;
}
Prog*
appendp(Link *ctxt, Prog *q)
{
Prog *p;
p = ctxt->arch->prg();
p->link = q->link;
q->link = p;
p->lineno = q->lineno;
p->mode = q->mode;
return p;
}
vlong
atolwhex(char *s)
{
vlong 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;
}

403
src/liblink/obj.c Normal file
View file

@ -0,0 +1,403 @@
// 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 <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
enum
{
HISTSZ = 10,
NSYM = 50,
};
int
linklinefmt(Link *ctxt, Fmt *fp)
{
struct
{
Hist* incl; /* start of this include file */
int32 idel; /* delta line number to apply to include */
Hist* line; /* start of this #line directive */
int32 ldel; /* delta line number to apply to #line */
} a[HISTSZ];
int32 lno, d;
int i, n;
Hist *h;
lno = va_arg(fp->args, int32);
n = 0;
for(h=ctxt->hist; h!=nil; h=h->link) {
if(h->offset < 0)
continue;
if(lno < h->line)
break;
if(h->name) {
if(h->offset > 0) {
// #line directive
if(n > 0 && n < HISTSZ) {
a[n-1].line = h;
a[n-1].ldel = h->line - h->offset + 1;
}
} else {
// beginning of file
if(n < HISTSZ) {
a[n].incl = h;
a[n].idel = h->line;
a[n].line = 0;
}
n++;
}
continue;
}
n--;
if(n > 0 && n < HISTSZ) {
d = h->line - a[n].incl->line;
a[n-1].ldel += d;
a[n-1].idel += d;
}
}
if(n > HISTSZ)
n = HISTSZ;
for(i=n-1; i>=0; i--) {
if(i != n-1) {
if(fp->flags & ~(FmtWidth|FmtPrec))
break;
fmtprint(fp, " ");
}
if(ctxt->debugline || (fp->flags&FmtLong))
fmtprint(fp, "%s/", ctxt->pathname);
if(a[i].line)
fmtprint(fp, "%s:%d[%s:%d]",
a[i].line->name, lno-a[i].ldel+1,
a[i].incl->name, lno-a[i].idel+1);
else
fmtprint(fp, "%s:%d",
a[i].incl->name, lno-a[i].idel+1);
lno = a[i].incl->line - 1; // now print out start of this file
}
if(n == 0)
fmtprint(fp, "<unknown line number>");
return 0;
}
static void
outzfile(Link *ctxt, Biobuf *b, char *p)
{
char *q, *q2;
while(p) {
q = utfrune(p, '/');
if(ctxt->windows) {
q2 = utfrune(p, '\\');
if(q2 && (!q || q2 < q))
q = q2;
}
if(!q) {
ctxt->arch->zfile(b, p, strlen(p));
return;
}
if(q > p)
ctxt->arch->zfile(b, p, q-p);
p = q + 1;
}
}
#define isdelim(c) (c == '/' || c == '\\')
static void
outwinname(Link *ctxt, Biobuf *b, Hist *h, char *ds, char *p)
{
if(isdelim(p[0])) {
// full rooted name
ctxt->arch->zfile(b, ds, 3); // leading "c:/"
outzfile(ctxt, b, p+1);
} else {
// relative name
if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[1] == ':') {
if(tolowerrune(ds[0]) == tolowerrune(ctxt->pathname[0])) {
// using current drive
ctxt->arch->zfile(b, ctxt->pathname, 3); // leading "c:/"
outzfile(ctxt, b, ctxt->pathname+3);
} else {
// using drive other then current,
// we don't have any simple way to
// determine current working directory
// there, therefore will output name as is
ctxt->arch->zfile(b, ds, 2); // leading "c:"
}
}
outzfile(ctxt, b, p);
}
}
void
linkouthist(Link *ctxt, Biobuf *b)
{
Hist *h;
char *p, ds[] = {'c', ':', '/', 0};
char *tofree;
int n;
static int first = 1;
static char *goroot, *goroot_final;
if(first) {
// Decide whether we need to rewrite paths from $GOROOT to $GOROOT_FINAL.
first = 0;
goroot = getenv("GOROOT");
goroot_final = getenv("GOROOT_FINAL");
if(goroot == nil)
goroot = "";
if(goroot_final == nil)
goroot_final = goroot;
if(strcmp(goroot, goroot_final) == 0) {
goroot = nil;
goroot_final = nil;
}
}
tofree = nil;
for(h = ctxt->hist; h != nil; h = h->link) {
p = h->name;
if(p) {
if(goroot != nil) {
n = strlen(goroot);
if(strncmp(p, goroot, strlen(goroot)) == 0 && p[n] == '/') {
tofree = smprint("%s%s", goroot_final, p+n);
p = tofree;
}
}
if(ctxt->windows) {
// if windows variable is set, then, we know already,
// pathname is started with windows drive specifier
// and all '\' were replaced with '/' (see lex.c)
if(isdelim(p[0]) && isdelim(p[1])) {
// file name has network name in it,
// like \\server\share\dir\file.go
ctxt->arch->zfile(b, "//", 2); // leading "//"
outzfile(ctxt, b, p+2);
} else if(p[1] == ':') {
// file name has drive letter in it
ds[0] = p[0];
outwinname(ctxt, b, h, ds, p+2);
} else {
// no drive letter in file name
outwinname(ctxt, b, h, ctxt->pathname, p);
}
} else {
if(p[0] == '/') {
// full rooted name, like /home/rsc/dir/file.go
ctxt->arch->zfile(b, "/", 1); // leading "/"
outzfile(ctxt, b, p+1);
} else {
// relative name, like dir/file.go
if(h->offset >= 0 && ctxt->pathname && ctxt->pathname[0] == '/') {
ctxt->arch->zfile(b, "/", 1); // leading "/"
outzfile(ctxt, b, ctxt->pathname+1);
}
outzfile(ctxt, b, p);
}
}
}
ctxt->arch->zhist(b, h->line, h->offset);
if(tofree) {
free(tofree);
tofree = nil;
}
}
}
void
linklinehist(Link *ctxt, int lineno, char *f, int offset)
{
Hist *h;
if(0) // debug['f']
if(f) {
if(offset)
print("%4d: %s (#line %d)\n", lineno, f, offset);
else
print("%4d: %s\n", lineno, f);
} else
print("%4d: <pop>\n", lineno);
h = malloc(sizeof(Hist));
memset(h, 0, sizeof *h);
h->name = f;
h->line = lineno;
h->offset = offset;
h->link = nil;
if(ctxt->ehist == nil) {
ctxt->hist = h;
ctxt->ehist = h;
return;
}
ctxt->ehist->link = h;
ctxt->ehist = h;
}
void
linkprfile(Link *ctxt, int32 l)
{
int i, n;
Hist a[HISTSZ], *h;
int32 d;
n = 0;
for(h = ctxt->hist; h != nil; h = h->link) {
if(l < h->line)
break;
if(h->name) {
if(h->offset == 0) {
if(n >= 0 && n < HISTSZ)
a[n] = *h;
n++;
continue;
}
if(n > 0 && n < HISTSZ)
if(a[n-1].offset == 0) {
a[n] = *h;
n++;
} else
a[n-1] = *h;
continue;
}
n--;
if(n >= 0 && n < HISTSZ) {
d = h->line - a[n].line;
for(i=0; i<n; i++)
a[i].line += d;
}
}
if(n > HISTSZ)
n = HISTSZ;
for(i=0; i<n; i++)
print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
}
/*
* start a new Prog list.
*/
Plist*
linknewplist(Link *ctxt)
{
Plist *pl;
pl = malloc(sizeof(*pl));
memset(pl, 0, sizeof *pl);
if(ctxt->plist == nil)
ctxt->plist = pl;
else
ctxt->plast->link = pl;
ctxt->plast = pl;
return pl;
}
static struct {
struct { LSym *sym; short type; } h[NSYM];
int sym;
} z;
static void
zsymreset(void)
{
for(z.sym=0; z.sym<NSYM; z.sym++) {
z.h[z.sym].sym = nil;
z.h[z.sym].type = 0;
}
z.sym = 1;
}
static int
zsym(Link *ctxt, Biobuf *b, LSym *s, int t, int *new)
{
int i;
*new = 0;
if(s == nil)
return 0;
i = s->symid;
if(i < 0 || i >= NSYM)
i = 0;
if(z.h[i].type == t && z.h[i].sym == s)
return i;
i = z.sym;
s->symid = i;
ctxt->arch->zname(b, s, t);
z.h[i].sym = s;
z.h[i].type = t;
if(++z.sym >= NSYM)
z.sym = 1;
*new = 1;
return i;
}
static int
zsymaddr(Link *ctxt, Biobuf *b, Addr *a, int *new)
{
return zsym(ctxt, b, a->sym, ctxt->arch->symtype(a), new);
}
void
linkwritefuncs(Link *ctxt, Biobuf *b)
{
int32 pcloc;
Plist *pl;
LSym *s;
Prog *p;
int sf, st, gf, gt, new;
zsymreset();
// fix up pc
pcloc = 0;
for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
continue;
for(p=pl->firstpc; p!=nil; p=p->link) {
p->loc = pcloc;
if(!ctxt->arch->isdata(p))
pcloc++;
}
}
// put out functions
for(pl=ctxt->plist; pl!=nil; pl=pl->link) {
if(pl->name != nil && strcmp(pl->name->name, "_") == 0)
continue;
// -S prints code; -S -S prints code and data
if(ctxt->debugasm && (pl->name || ctxt->debugasm>1)) {
s = pl->name;
print("\n--- prog list \"%lS\" ---\n", s);
for(p=pl->firstpc; p!=nil; p=p->link)
print("%P\n", p);
}
for(p=pl->firstpc; p!=nil; p=p->link) {
for(;;) {
sf = zsymaddr(ctxt, b, &p->from, &new);
gf = zsym(ctxt, b, p->from.gotype, ctxt->arch->D_EXTERN, &new);
if(new && sf == gf)
continue;
st = zsymaddr(ctxt, b, &p->to, &new);
if(new && (st == sf || st == gf))
continue;
gt = zsym(ctxt, b, p->to.gotype, ctxt->arch->D_EXTERN, &new);
if(new && (gt == sf || gt == gf || gt == st))
continue;
break;
}
ctxt->arch->zprog(ctxt, b, p, sf, gf, st, gt);
}
}
}

1187
src/liblink/obj5.c Normal file

File diff suppressed because it is too large Load diff

1078
src/liblink/obj6.c Normal file

File diff suppressed because it is too large Load diff

937
src/liblink/obj8.c Normal file
View file

@ -0,0 +1,937 @@
// Inferno utils/8l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/8l/8.out.h"
#include "../pkg/runtime/stack.h"
static Addr noaddr = {
.type = D_NONE,
.index = D_NONE,
.scale = 1,
};
static Prog zprg = {
.back = 2,
.as = AGOK,
.from = {
.type = D_NONE,
.index = D_NONE,
.scale = 1,
},
.to = {
.type = D_NONE,
.index = D_NONE,
.scale = 1,
},
};
static void
zname(Biobuf *b, LSym *s, int t)
{
BPUTLE2(b, ANAME); /* as */
BPUTC(b, t); /* type */
BPUTC(b, s->symid); /* sym */
Bwrite(b, s->name, strlen(s->name)+1);
}
static void
zfile(Biobuf *b, char *p, int n)
{
BPUTLE2(b, ANAME);
BPUTC(b, D_FILE);
BPUTC(b, 1);
BPUTC(b, '<');
Bwrite(b, p, n);
BPUTC(b, 0);
}
static void
zaddr(Biobuf *b, Addr *a, int s, int gotype)
{
int32 l;
uint64 e;
int i, t;
char *n;
t = 0;
if(a->index != D_NONE || a->scale != 0)
t |= T_INDEX;
if(s != 0)
t |= T_SYM;
if(gotype != 0)
t |= T_GOTYPE;
switch(a->type) {
case D_BRANCH:
if(a->offset == 0 || a->u.branch != nil) {
if(a->u.branch == nil)
sysfatal("unpatched branch %D", a);
a->offset = a->u.branch->loc;
}
default:
t |= T_TYPE;
case D_NONE:
if(a->offset != 0)
t |= T_OFFSET;
if(a->offset2 != 0)
t |= T_OFFSET2;
break;
case D_FCONST:
t |= T_FCONST;
break;
case D_SCONST:
t |= T_SCONST;
break;
}
BPUTC(b, t);
if(t & T_INDEX) { /* implies index, scale */
BPUTC(b, a->index);
BPUTC(b, a->scale);
}
if(t & T_OFFSET) { /* implies offset */
l = a->offset;
BPUTLE4(b, l);
}
if(t & T_OFFSET2) { /* implies offset */
l = a->offset2;
BPUTLE4(b, l);
}
if(t & T_SYM) /* implies sym */
BPUTC(b, s);
if(t & T_FCONST) {
double2ieee(&e, a->u.dval);
BPUTLE4(b, e);
BPUTLE4(b, e >> 32);
return;
}
if(t & T_SCONST) {
n = a->u.sval;
for(i=0; i<NSNAME; i++) {
BPUTC(b, *n);
n++;
}
return;
}
if(t & T_TYPE)
BPUTC(b, a->type);
if(t & T_GOTYPE)
BPUTC(b, gotype);
}
static void
zhist(Biobuf *b, int line, vlong offset)
{
Addr a;
BPUTLE2(b, AHISTORY);
BPUTLE4(b, line);
zaddr(b, &noaddr, 0, 0);
a = noaddr;
if(offset != 0) {
a.offset = offset;
a.type = D_CONST;
}
zaddr(b, &a, 0, 0);
}
static int
symtype(Addr *a)
{
int t;
t = a->type;
if(t == D_ADDR)
t = a->index;
return t;
}
static void
zprog(Link *ctxt, Biobuf *b, Prog *p, int sf, int gf, int st, int gt)
{
USED(ctxt);
BPUTLE2(b, p->as);
BPUTLE4(b, p->lineno);
zaddr(b, &p->from, sf, gf);
zaddr(b, &p->to, st, gt);
}
static int
isdata(Prog *p)
{
return p->as == ADATA || p->as == AGLOBL;
}
static int
iscall(Prog *p)
{
return p->as == ACALL;
}
static int
datasize(Prog *p)
{
return p->from.scale;
}
static int
textflag(Prog *p)
{
return p->from.scale;
}
static void
settextflag(Prog *p, int f)
{
p->from.scale = f;
}
static void
progedit(Link *ctxt, Prog *p)
{
Prog *q;
if(ctxt->headtype == Hwindows) {
// Convert
// op n(GS), reg
// to
// 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
// a different method is used to access them.
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(ctxt, p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x14;
}
}
if(ctxt->headtype == Hlinux) {
// Running binaries under Xen requires using
// MOVL 0(GS), reg
// and then off(reg) instead of saying off(GS) directly
// when the offset is negative.
// In external mode we just produce a reloc.
if(p->from.type == D_INDIR+D_GS && p->from.offset < 0
&& p->to.type >= D_AX && p->to.type <= D_DI) {
if(ctxt->linkmode != LinkExternal) {
q = appendp(ctxt, p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0;
} else {
// Add signals to relocate.
p->from.index = D_GS;
p->from.scale = 1;
}
}
}
/* TODO
if(ctxt->headtype == Hplan9) {
if(p->from.type == D_INDIR+D_GS
&& p->to.type >= D_AX && p->to.type <= D_DI) {
q = appendp(ctxt, p);
q->from = p->from;
q->from.type = D_INDIR + p->to.type;
q->to = p->to;
q->as = p->as;
p->as = AMOVL;
p->from.type = D_EXTERN;
p->from.sym = plan9_tos;
p->from.offset = 0;
}
}
*/
}
static Prog*
prg(void)
{
Prog *p;
p = emallocz(sizeof(*p));
*p = zprg;
return p;
}
static Prog* load_g_cx(Link*, Prog*);
static Prog* stacksplit(Link*, Prog*, int32, Prog**);
static void
addstacksplit(Link *ctxt, LSym *cursym)
{
Prog *p, *q;
int32 autoffset, deltasp;
int a;
if(ctxt->symmorestack[0] == nil)
ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
if(ctxt->headtype == Hplan9 && ctxt->plan9tos == nil)
ctxt->plan9tos = linklookup(ctxt, "_tos", 0);
ctxt->cursym = cursym;
if(cursym->text == nil || cursym->text->link == nil)
return;
p = cursym->text;
autoffset = p->to.offset;
if(autoffset < 0)
autoffset = 0;
q = nil;
if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
p = appendp(ctxt, p);
p = load_g_cx(ctxt, p); // load g into CX
}
if(!(cursym->text->from.scale & NOSPLIT))
p = stacksplit(ctxt, p, autoffset, &q); // emit split check
if(autoffset) {
p = appendp(ctxt, p);
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = autoffset;
p->spadj = autoffset;
} else {
// zero-byte stack adjustment.
// Insert a fake non-zero adjustment so that stkcheck can
// recognize the end of the stack-splitting prolog.
p = appendp(ctxt, p);
p->as = ANOP;
p->spadj = -ctxt->arch->ptrsize;
p = appendp(ctxt, p);
p->as = ANOP;
p->spadj = ctxt->arch->ptrsize;
}
if(q != nil)
q->pcond = p;
deltasp = autoffset;
if(cursym->text->from.scale & WRAPPER) {
// g->panicwrap += autoffset + ctxt->arch->ptrsize;
p = appendp(ctxt, p);
p->as = AADDL;
p->from.type = D_CONST;
p->from.offset = autoffset + ctxt->arch->ptrsize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*ctxt->arch->ptrsize;
}
if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
// 8l -Z means zero the stack frame on entry.
// This slows down function calls but can help avoid
// false positives in garbage collection.
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_SP;
p->to.type = D_DI;
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = autoffset/4;
p->to.type = D_CX;
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_CONST;
p->from.offset = 0;
p->to.type = D_AX;
p = appendp(ctxt, p);
p->as = AREP;
p = appendp(ctxt, p);
p->as = ASTOSL;
}
for(; p != nil; p = p->link) {
a = p->from.type;
if(a == D_AUTO)
p->from.offset += deltasp;
if(a == D_PARAM)
p->from.offset += deltasp + 4;
a = p->to.type;
if(a == D_AUTO)
p->to.offset += deltasp;
if(a == D_PARAM)
p->to.offset += deltasp + 4;
switch(p->as) {
default:
continue;
case APUSHL:
case APUSHFL:
deltasp += 4;
p->spadj = 4;
continue;
case APUSHW:
case APUSHFW:
deltasp += 2;
p->spadj = 2;
continue;
case APOPL:
case APOPFL:
deltasp -= 4;
p->spadj = -4;
continue;
case APOPW:
case APOPFW:
deltasp -= 2;
p->spadj = -2;
continue;
case ARET:
break;
}
if(autoffset != deltasp)
ctxt->diag("unbalanced PUSH/POP");
if(cursym->text->from.scale & WRAPPER) {
p = load_g_cx(ctxt, p);
p = appendp(ctxt, p);
// g->panicwrap -= autoffset + ctxt->arch->ptrsize;
p->as = ASUBL;
p->from.type = D_CONST;
p->from.offset = autoffset + ctxt->arch->ptrsize;
p->to.type = D_INDIR+D_CX;
p->to.offset = 2*ctxt->arch->ptrsize;
p = appendp(ctxt, p);
p->as = ARET;
}
if(autoffset) {
p->as = AADJSP;
p->from.type = D_CONST;
p->from.offset = -autoffset;
p->spadj = -autoffset;
p = appendp(ctxt, p);
p->as = ARET;
// If there are instructions following
// this ARET, they come from a branch
// with the same stackframe, so undo
// the cleanup.
p->spadj = +autoffset;
}
if(p->to.sym) // retjmp
p->as = AJMP;
}
}
// Append code to p to load g into cx.
// Overwrites p with the first instruction (no first appendp).
// Overwriting p is unusual but it lets use this in both the
// prologue (caller must call appendp first) and in the epilogue.
// Returns last new instruction.
static Prog*
load_g_cx(Link *ctxt, Prog *p)
{
switch(ctxt->headtype) {
case Hwindows:
p->as = AMOVL;
p->from.type = D_INDIR+D_FS;
p->from.offset = 0x14;
p->to.type = D_CX;
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_CX;
break;
case Hlinux:
if(ctxt->linkmode != LinkExternal) {
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = 0;
p->to.type = D_CX;
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = ctxt->tlsoffset + 0;
p->to.type = D_CX;
} else {
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = ctxt->tlsoffset + 0;
p->to.type = D_CX;
p->from.index = D_GS;
p->from.scale = 1;
}
break;
case Hplan9:
p->as = AMOVL;
p->from.type = D_EXTERN;
p->from.sym = ctxt->plan9tos;
p->to.type = D_CX;
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = ctxt->tlsoffset + 0;
p->to.type = D_CX;
break;
default:
p->as = AMOVL;
p->from.type = D_INDIR+D_GS;
p->from.offset = ctxt->tlsoffset + 0;
p->to.type = D_CX;
}
return p;
}
// Append code to p to check for stack split.
// Appends to (does not overwrite) p.
// Assumes g is in CX.
// Returns last new instruction.
// On return, *jmpok is the instruction that should jump
// to the stack frame allocation if no split is needed.
static Prog*
stacksplit(Link *ctxt, Prog *p, int32 framesize, Prog **jmpok)
{
Prog *q, *q1;
int arg;
if(ctxt->debugstack) {
// 8l -K means check not only for stack
// overflow but stack underflow.
// On underflow, INT 3 (breakpoint).
// Underflow itself is rare but this also
// catches out-of-sync stack guard info.
p = appendp(ctxt, p);
p->as = ACMPL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 4;
p->to.type = D_SP;
p = appendp(ctxt, p);
p->as = AJCC;
p->to.type = D_BRANCH;
p->to.offset = 4;
q1 = p;
p = appendp(ctxt, p);
p->as = AINT;
p->from.type = D_CONST;
p->from.offset = 3;
p = appendp(ctxt, p);
p->as = ANOP;
q1->pcond = p;
}
q1 = nil;
if(framesize <= StackSmall) {
// small stack: SP <= stackguard
// CMPL SP, stackguard
p = appendp(ctxt, p);
p->as = ACMPL;
p->from.type = D_SP;
p->to.type = D_INDIR+D_CX;
} else if(framesize <= StackBig) {
// large stack: SP-framesize <= stackguard-StackSmall
// LEAL -(framesize-StackSmall)(SP), AX
// CMPL AX, stackguard
p = appendp(ctxt, p);
p->as = ALEAL;
p->from.type = D_INDIR+D_SP;
p->from.offset = -(framesize-StackSmall);
p->to.type = D_AX;
p = appendp(ctxt, p);
p->as = ACMPL;
p->from.type = D_AX;
p->to.type = D_INDIR+D_CX;
} 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.
//
// Preemption sets stackguard to StackPreempt, a very large value.
// That breaks the math above, so we have to check for that explicitly.
// MOVL stackguard, CX
// CMPL CX, $StackPreempt
// JEQ label-of-call-to-morestack
// LEAL StackGuard(SP), AX
// SUBL stackguard, AX
// CMPL AX, $(framesize+(StackGuard-StackSmall))
p = appendp(ctxt, p);
p->as = AMOVL;
p->from.type = D_INDIR+D_CX;
p->from.offset = 0;
p->to.type = D_SI;
p = appendp(ctxt, p);
p->as = ACMPL;
p->from.type = D_SI;
p->to.type = D_CONST;
p->to.offset = (uint32)StackPreempt;
p = appendp(ctxt, p);
p->as = AJEQ;
p->to.type = D_BRANCH;
q1 = p;
p = appendp(ctxt, p);
p->as = ALEAL;
p->from.type = D_INDIR+D_SP;
p->from.offset = StackGuard;
p->to.type = D_AX;
p = appendp(ctxt, p);
p->as = ASUBL;
p->from.type = D_SI;
p->from.offset = 0;
p->to.type = D_AX;
p = appendp(ctxt, p);
p->as = ACMPL;
p->from.type = D_AX;
p->to.type = D_CONST;
p->to.offset = framesize+(StackGuard-StackSmall);
}
// common
p = appendp(ctxt, p);
p->as = AJHI;
p->to.type = D_BRANCH;
p->to.offset = 4;
q = p;
p = appendp(ctxt, p); // save frame size in DI
p->as = AMOVL;
p->to.type = D_DI;
p->from.type = D_CONST;
// 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 + ctxt->cursym->text->to.offset2 + ctxt->arch->ptrsize + framesize + ctxt->arch->ptrsize + StackLimit >= StackMin)
p->from.offset = (framesize+7) & ~7LL;
arg = ctxt->cursym->text->to.offset2;
if(arg == 1) // special marker for known 0
arg = 0;
if(arg&3)
ctxt->diag("misaligned argument size in stack split");
p = appendp(ctxt, p); // save arg size in AX
p->as = AMOVL;
p->to.type = D_AX;
p->from.type = D_CONST;
p->from.offset = arg;
p = appendp(ctxt, p);
p->as = ACALL;
p->to.type = D_BRANCH;
p->to.sym = ctxt->symmorestack[0];
p = appendp(ctxt, p);
p->as = AJMP;
p->to.type = D_BRANCH;
p->pcond = ctxt->cursym->text->link;
if(q != nil)
q->pcond = p->link;
if(q1 != nil)
q1->pcond = q->link;
*jmpok = q;
return p;
}
static void xfol(Link*, Prog*, Prog**);
static void
follow(Link *ctxt, LSym *s)
{
Prog *firstp, *lastp;
ctxt->cursym = s;
firstp = ctxt->arch->prg();
lastp = firstp;
xfol(ctxt, s->text, &lastp);
lastp->link = nil;
s->text = firstp->link;
}
static int
nofollow(int a)
{
switch(a) {
case AJMP:
case ARET:
case AIRETL:
case AIRETW:
case AUNDEF:
return 1;
}
return 0;
}
static int
pushpop(int a)
{
switch(a) {
case APUSHL:
case APUSHFL:
case APUSHW:
case APUSHFW:
case APOPL:
case APOPFL:
case APOPW:
case APOPFW:
return 1;
}
return 0;
}
static int
relinv(int a)
{
switch(a) {
case AJEQ: return AJNE;
case AJNE: return AJEQ;
case AJLE: return AJGT;
case AJLS: return AJHI;
case AJLT: return AJGE;
case AJMI: return AJPL;
case AJGE: return AJLT;
case AJPL: return AJMI;
case AJGT: return AJLE;
case AJHI: return AJLS;
case AJCS: return AJCC;
case AJCC: return AJCS;
case AJPS: return AJPC;
case AJPC: return AJPS;
case AJOS: return AJOC;
case AJOC: return AJOS;
}
sysfatal("unknown relation: %s", anames8[a]);
return 0;
}
static void
xfol(Link *ctxt, Prog *p, Prog **last)
{
Prog *q;
int i;
enum as a;
loop:
if(p == nil)
return;
if(p->as == AJMP)
if((q = p->pcond) != nil && q->as != ATEXT) {
/* mark instruction as done and continue layout at target of jump */
p->mark = 1;
p = q;
if(p->mark == 0)
goto loop;
}
if(p->mark) {
/*
* p goes here, but already used it elsewhere.
* copy up to 4 instructions or else branch to other copy.
*/
for(i=0,q=p; i<4; i++,q=q->link) {
if(q == nil)
break;
if(q == *last)
break;
a = q->as;
if(a == ANOP) {
i--;
continue;
}
if(nofollow(a) || pushpop(a))
break; // NOTE(rsc): arm does goto copy
if(q->pcond == nil || q->pcond->mark)
continue;
if(a == ACALL || a == ALOOP)
continue;
for(;;) {
if(p->as == ANOP) {
p = p->link;
continue;
}
q = copyp(ctxt, p);
p = p->link;
q->mark = 1;
(*last)->link = q;
*last = q;
if(q->as != a || q->pcond == nil || q->pcond->mark)
continue;
q->as = relinv(q->as);
p = q->pcond;
q->pcond = q->link;
q->link = p;
xfol(ctxt, q->link, last);
p = q->link;
if(p->mark)
return;
goto loop;
}
} /* */
q = ctxt->arch->prg();
q->as = AJMP;
q->lineno = p->lineno;
q->to.type = D_BRANCH;
q->to.offset = p->pc;
q->pcond = p;
p = q;
}
/* emit p */
p->mark = 1;
(*last)->link = p;
*last = p;
a = p->as;
/* continue loop with what comes after p */
if(nofollow(a))
return;
if(p->pcond != nil && a != ACALL) {
/*
* some kind of conditional branch.
* recurse to follow one path.
* continue loop on the other.
*/
if((q = brchain(ctxt, p->pcond)) != nil)
p->pcond = q;
if((q = brchain(ctxt, p->link)) != nil)
p->link = q;
if(p->from.type == D_CONST) {
if(p->from.offset == 1) {
/*
* expect conditional jump to be taken.
* rewrite so that's the fall-through case.
*/
p->as = relinv(a);
q = p->link;
p->link = p->pcond;
p->pcond = q;
}
} else {
q = p->link;
if(q->mark)
if(a != ALOOP) {
p->as = relinv(a);
p->link = p->pcond;
p->pcond = q;
}
}
xfol(ctxt, p->link, last);
if(p->pcond->mark)
return;
p = p->pcond;
goto loop;
}
p = p->link;
goto loop;
}
LinkArch link386 = {
.name = "386",
.addstacksplit = addstacksplit,
.assemble = span8,
.datasize = datasize,
.follow = follow,
.iscall = iscall,
.isdata = isdata,
.ldobj = ldobj8,
.nopout = nopout8,
.prg = prg,
.progedit = progedit,
.settextflag = settextflag,
.symtype = symtype,
.textflag = textflag,
.zfile = zfile,
.zhist = zhist,
.zname = zname,
.zprog = zprog,
.minlc = 1,
.ptrsize = 4,
.D_ADDR = D_ADDR,
.D_BRANCH = D_BRANCH,
.D_CONST = D_CONST,
.D_EXTERN = D_EXTERN,
.D_FCONST = D_FCONST,
.D_NONE = D_NONE,
.D_PCREL = D_PCREL,
.D_SCONST = D_SCONST,
.D_SIZE = D_SIZE,
.ACALL = ACALL,
.AFUNCDATA = AFUNCDATA,
.AJMP = AJMP,
.ANOP = ANOP,
.APCDATA = APCDATA,
.ARET = ARET,
.ATEXT = ATEXT,
.AUSEFIELD = AUSEFIELD,
};

115
src/liblink/pass.c Normal file
View file

@ -0,0 +1,115 @@
// Inferno utils/6l/pass.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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 <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
Prog*
brchain(Link *ctxt, Prog *p)
{
int i;
for(i=0; i<20; i++) {
if(p == nil || p->as != ctxt->arch->AJMP)
return p;
p = p->pcond;
}
return nil;
}
Prog*
brloop(Link *ctxt, Prog *p)
{
int c;
Prog *q;
c = 0;
for(q = p; q != nil; q = q->pcond) {
if(q->as != ctxt->arch->AJMP)
break;
c++;
if(c >= 5000)
return nil;
}
return q;
}
void
linkpatch(Link *ctxt, LSym *sym)
{
int32 c;
Prog *p, *q;
LSym *s;
ctxt->cursym = sym;
for(p = sym->text; p != nil; p = p->link) {
if(ctxt->arch->progedit)
ctxt->arch->progedit(ctxt, p);
if(p->as == ctxt->arch->ACALL || (p->as == ctxt->arch->AJMP && p->to.type != ctxt->arch->D_BRANCH) || (p->as == ctxt->arch->ARET && p->to.sym != nil)) {
s = p->to.sym;
if(s) {
p->to.type = ctxt->arch->D_BRANCH;
continue;
}
}
if(p->to.type != ctxt->arch->D_BRANCH)
continue;
c = p->to.offset;
for(q = sym->text; q != nil;) {
if(c == q->pc)
break;
if(q->forwd != nil && c >= q->forwd->pc)
q = q->forwd;
else
q = q->link;
}
if(q == nil) {
ctxt->diag("branch out of range (%#ux)\n%P [%s]",
c, p, p->to.sym ? p->to.sym->name : "<nil>");
p->to.type = ctxt->arch->D_NONE;
}
p->pcond = q;
}
for(p = sym->text; p != nil; p = p->link) {
p->mark = 0; /* initialization for follow */
if(p->pcond != nil) {
p->pcond = brloop(ctxt, p->pcond);
if(p->pcond != nil)
if(p->to.type == ctxt->arch->D_BRANCH)
p->to.offset = p->pcond->pc;
}
}
}

298
src/liblink/pcln.c Normal file
View file

@ -0,0 +1,298 @@
// Copyright 2013 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 <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
static void
addvarint(Link *ctxt, Pcdata *d, uint32 val)
{
int32 n;
uint32 v;
uchar *p;
USED(ctxt);
n = 0;
for(v = val; v >= 0x80; v >>= 7)
n++;
n++;
if(d->n + n > d->m) {
d->m = (d->n + n)*2;
d->p = erealloc(d->p, d->m);
}
p = d->p + d->n;
for(v = val; v >= 0x80; v >>= 7)
*p++ = v | 0x80;
*p++ = v;
d->n += n;
}
// funcpctab writes to dst a pc-value table mapping the code in func to the values
// returned by valfunc parameterized by arg. The invocation of valfunc to update the
// current value is, for each p,
//
// val = valfunc(func, val, p, 0, arg);
// record val as value at p->pc;
// val = valfunc(func, val, p, 1, arg);
//
// where func is the function, val is the current value, p is the instruction being
// considered, and arg can be used to further parameterize valfunc.
static void
funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
{
int dbg, i;
int32 oldval, val, started;
uint32 delta;
vlong pc;
Prog *p;
// To debug a specific function, uncomment second line and change name.
dbg = 0;
//dbg = strcmp(func->name, "main.main") == 0;
//dbg = strcmp(desc, "pctofile") == 0;
ctxt->debugpcln += dbg;
dst->n = 0;
if(ctxt->debugpcln)
Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
val = -1;
oldval = val;
if(func->text == nil)
return;
pc = func->text->pc;
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
started = 0;
for(p=func->text; p != nil; p = p->link) {
// Update val. If it's not changing, keep going.
val = valfunc(ctxt, func, val, p, 0, arg);
if(val == oldval && started) {
val = valfunc(ctxt, func, val, p, 1, arg);
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
continue;
}
// If the pc of the next instruction is the same as the
// pc of this instruction, this instruction is not a real
// instruction. Keep going, so that we only emit a delta
// for a true instruction boundary in the program.
if(p->link && p->link->pc == p->pc) {
val = valfunc(ctxt, func, val, p, 1, arg);
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
continue;
}
// The table is a sequence of (value, pc) pairs, where each
// pair states that the given value is in effect from the current position
// up to the given pc, which becomes the new current position.
// To generate the table as we scan over the program instructions,
// we emit a "(value" when pc == func->value, and then
// each time we observe a change in value we emit ", pc) (value".
// When the scan is over, we emit the closing ", pc)".
//
// The table is delta-encoded. The value deltas are signed and
// transmitted in zig-zag form, where a complement bit is placed in bit 0,
// and the pc deltas are unsigned. Both kinds of deltas are sent
// as variable-length little-endian base-128 integers,
// where the 0x80 bit indicates that the integer continues.
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
if(started) {
addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
pc = p->pc;
}
delta = val - oldval;
if(delta>>31)
delta = 1 | ~(delta<<1);
else
delta <<= 1;
addvarint(ctxt, dst, delta);
oldval = val;
started = 1;
val = valfunc(ctxt, func, val, p, 1, arg);
}
if(started) {
if(ctxt->debugpcln)
Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
addvarint(ctxt, dst, 0); // terminator
}
if(ctxt->debugpcln) {
Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
for(i=0; i<dst->n; i++)
Bprint(ctxt->bso, " %02ux", dst->p[i]);
Bprint(ctxt->bso, "\n");
}
ctxt->debugpcln -= dbg;
}
// pctofileline computes either the file number (arg == 0)
// or the line number (arg == 1) to use at p.
// Because p->lineno applies to p, phase == 0 (before p)
// takes care of the update.
static int32
pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
int32 i, l;
LSym *f;
Pcln *pcln;
if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
return oldval;
linkgetline(ctxt, sym->hist, p->lineno, &f, &l);
if(f == nil) {
// print("getline failed for %s %P\n", ctxt->cursym->name, p);
return oldval;
}
if(arg == nil)
return l;
pcln = arg;
if(f == pcln->lastfile)
return pcln->lastindex;
for(i=0; i<pcln->nfile; i++) {
if(pcln->file[i] == f) {
pcln->lastfile = f;
pcln->lastindex = i;
return i;
}
}
if(pcln->nfile >= pcln->mfile) {
pcln->mfile = (pcln->nfile+1)*2;
pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
}
pcln->file[pcln->nfile++] = f;
pcln->lastfile = f;
pcln->lastindex = i;
return i;
}
// pctospadj computes the sp adjustment in effect.
// It is oldval plus any adjustment made by p itself.
// The adjustment by p takes effect only after p, so we
// apply the change during phase == 1.
static int32
pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
USED(arg);
USED(sym);
if(oldval == -1) // starting
oldval = 0;
if(phase == 0)
return oldval;
if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
sysfatal("bad code");
}
return oldval + p->spadj;
}
// pctopcdata computes the pcdata value in effect at p.
// A PCDATA instruction sets the value in effect at future
// non-PCDATA instructions.
// Since PCDATA instructions have no width in the final code,
// it does not matter which phase we use for the update.
static int32
pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
{
USED(sym);
if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
return oldval;
if((int32)p->to.offset != p->to.offset) {
ctxt->diag("overflow in PCDATA instruction: %P", p);
sysfatal("bad code");
}
return p->to.offset;
}
void
linkpcln(Link *ctxt, LSym *cursym)
{
Prog *p;
Pcln *pcln;
int i, npcdata, nfuncdata, n;
uint32 *havepc, *havefunc;
ctxt->cursym = cursym;
pcln = emallocz(sizeof *pcln);
cursym->pcln = pcln;
npcdata = 0;
nfuncdata = 0;
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
npcdata = p->from.offset+1;
if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
nfuncdata = p->from.offset+1;
}
pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
pcln->npcdata = npcdata;
pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
pcln->nfuncdata = nfuncdata;
funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
// tabulate which pc and func data we have.
n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
havepc = emallocz(n);
havefunc = havepc + (npcdata+31)/32;
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->AFUNCDATA) {
if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
if(p->as == ctxt->arch->APCDATA)
havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
}
// pcdata.
for(i=0; i<npcdata; i++) {
if(!(havepc[i/32]>>(i%32))&1)
continue;
funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
}
free(havepc);
// funcdata
if(nfuncdata > 0) {
for(p = cursym->text; p != nil; p = p->link) {
if(p->as == ctxt->arch->AFUNCDATA) {
i = p->from.offset;
pcln->funcdataoff[i] = p->to.offset;
if(p->to.type != ctxt->arch->D_CONST) {
// TODO: Dedup.
//funcdata_bytes += p->to.sym->size;
pcln->funcdata[i] = p->to.sym;
}
}
}
}
}

585
src/liblink/rdobj5.c Normal file
View file

@ -0,0 +1,585 @@
// 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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/5l/5.out.h"
// TODO: remove duplicate chipzero, chipfloat
static void finish(Link*);
static int
chipzero(Link *ctxt, float64 e)
{
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
if(ctxt->goarm < 7 || e != 0)
return -1;
return 0;
}
static int
chipfloat(Link *ctxt, float64 e)
{
int n;
ulong h1;
int32 l, h;
uint64 ei;
// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
if(ctxt->goarm < 7)
goto no;
memmove(&ei, &e, 8);
l = (int32)ei;
h = (int32)(ei>>32);
if(l != 0 || (h&0xffff) != 0)
goto no;
h1 = h & 0x7fc00000;
if(h1 != 0x40000000 && h1 != 0x3fc00000)
goto no;
n = 0;
// sign bit (a)
if(h & 0x80000000)
n |= 1<<7;
// exp sign bit (b)
if(h1 == 0x3fc00000)
n |= 1<<6;
// rest of exp and mantissa (cd-efgh)
n |= (h >> 16) & 0x3f;
//print("match %.8lux %.8lux %d\n", l, h, n);
return n;
no:
return -1;
}
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o == 0)
return nil;
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int i, c;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
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);
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
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 != nil && (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:
Bread(f, a->u.sval, NSNAME);
break;
case D_FCONST:
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
break;
}
s = a->sym;
if(s == nil)
return;
i = a->name;
if(i != D_AUTO && i != D_PARAM) {
if(s && gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link)
if(u->asym == s)
if(u->type == i) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
u = emallocz(sizeof(Auto));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = i;
u->gotype = gotype;
}
void
nopout5(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj5(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
Prog *p;
LSym *h[NSYM], *s;
int v, o, r, skip;
uint32 sig;
char *name;
int ntext;
int32 eof, autosize;
char src[1024], *x, literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->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) {
ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
sysfatal("probably not a .5 file");
}
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 = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0) {
fprint(2, "%s: name too long\n", pn);
sysfatal("invalid object file");
}
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(sig != 0){
if(s->sig != 0 && s->sig != sig)
ctxt->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(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h)) {
fprint(2, "%s: mangled input file\n", pn);
sysfatal("invalid object");
}
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(Prog));
p->as = o;
p->scond = BGETC(f);
p->reg = BGETC(f);
p->lineno = BGETLE4(f);
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
if(p->as != ATEXT && p->as != AGLOBL && p->reg > NREG)
ctxt->diag("register out of range %A %d", p->as, p->reg);
p->link = nil;
p->pcond = nil;
if(ctxt->debugread)
print("%P\n", p);
switch(o) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s == nil) {
ctxt->diag("GLOBL must have a name\n%P", p);
sysfatal("mangled input");
}
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->value = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->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) {
ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
sysfatal("mangled input");
}
savedata(ctxt, s, p, pn);
free(p);
break;
case AGOK:
ctxt->diag("unknown opcode\n%P", p);
p->pc = ctxt->pc;
ctxt->pc++;
break;
case ATYPE:
if(skip)
goto casedef;
ctxt->pc++;
goto loop;
case ATEXT:
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
s = p->from.sym;
if(s == nil) {
ctxt->diag("TEXT must have a name\n%P", p);
sysfatal("mangled input");
}
ctxt->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(ctxt->debugvlog)
Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
skip = 0;
if(s->type != 0 && s->type != SXREF)
ctxt->diag("redefinition: %s\n%P", s->name, p);
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
if(fromgotype) {
if(s->gotype && s->gotype != fromgotype)
ctxt->diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
ctxt->etextp = s;
autosize = (p->to.offset+3L) & ~3L;
p->to.offset = autosize;
autosize += 4;
s->type = STEXT;
s->hist = gethist(ctxt);
s->text = p;
s->value = ctxt->pc;
s->args = p->to.offset2;
lastp = p;
p->pc = ctxt->pc;
ctxt->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(ctxt, p->from.u.dval) < 0 &&
(chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 9 max */
sprint(literal, "$%.17gf", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
float32 f32;
int32 i32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
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(ctxt, p->from.u.dval) < 0 &&
(chipzero(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
/* size sb 18 max */
sprint(literal, "$%.17g", p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
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)
nopout5(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
break;
}
lastp->link = p;
lastp = p;
break;
}
goto loop;
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}

495
src/liblink/rdobj6.c Normal file
View file

@ -0,0 +1,495 @@
// Inferno utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/6l/6.out.h"
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void finish(Link*);
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int t;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->offset = 0;
if(t & T_OFFSET) {
a->offset = BGETLE4(f);
if(t & T_64) {
a->offset &= 0xFFFFFFFFULL;
a->offset |= (uvlong)BGETLE4(f) << 32;
}
}
a->sym = nil;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
a->type = D_NONE;
if(t & T_FCONST) {
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->u.sval, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
if(a->type < 0 || a->type >= D_SIZE)
mangle(pn);
gotype = nil;
if(t & T_GOTYPE)
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
s = a->sym;
t = a->type;
if(t == D_INDIR+D_GS || a->index == D_GS)
a->offset += ctxt->tlsoffset;
if(t != D_AUTO && t != D_PARAM) {
if(s && gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
}
switch(t) {
case D_FILE:
case D_FILE1:
case D_AUTO:
case D_PARAM:
if(s == nil)
mangle(pn);
}
u = emallocz(sizeof(*u));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
u->gotype = gotype;
}
void
nopout6(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj6(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
vlong ipc;
Prog *p;
int v, o, r, skip, mode;
LSym *h[NSYM], *s;
uint32 sig;
char *name, *x;
int ntext;
vlong eof;
char src[1024], literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->pc;
skip = 0;
mode = 64;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
sysfatal("%s:#%lld: opcode out of range: %#ux\n\tprobably not a .6 file", pn, Boffset(f), o);
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME)
sig = BGETLE4(f);
USED(sig);
v = BGETC(f); /* type */
o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0)
sysfatal("%s: name too long", pn);
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h))
mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
if(ctxt->dwarfaddfrag)
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(*p));
p->as = o;
p->lineno = BGETLE4(f);
p->back = 2;
p->mode = mode;
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
switch(p->as) {
case ATEXT:
case ADATA:
case AGLOBL:
if(p->from.sym == nil)
mangle(pn);
break;
}
if(ctxt->debugread)
print("%P\n", p);
switch(p->as) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->diag("%s: redefinition: %s in %s",
pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
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(ctxt->debugvlog)
// 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)
sysfatal("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
savedata(ctxt, s, p, pn);
free(p);
goto loop;
case AGOK:
ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
ctxt->pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
ctxt->pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: %s: redefinition", pn, s->name);
return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(ctxt->debugvlog && ctxt->bso)
Bprint(ctxt->bso, "skipping: %s: redefinition: %s", pn, s->name);
return;
}
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
skip = 0;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
ctxt->etextp = s;
s->text = p;
ctxt->cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
if(fromgotype) {
if(s->gotype && s->gotype != fromgotype)
ctxt->diag("%s: type mismatch for %s", pn, s->name);
s->gotype = fromgotype;
}
s->type = STEXT;
s->hist = gethist(ctxt);
s->value = ctxt->pc;
s->args = p->to.offset >> 32;
lastp = p;
p->pc = ctxt->pc++;
goto loop;
case AMODE:
if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE){
switch((int)p->from.offset){
case 16: case 32: case 64:
mode = p->from.offset;
break;
}
}
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
sprint(literal, "$%.17gf", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int32 i32;
float32 f32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
sprint(literal, "$%.17g", p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
if(skip)
nopout6(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}

466
src/liblink/rdobj8.c Normal file
View file

@ -0,0 +1,466 @@
// Inferno utils/8l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
#include "../cmd/8l/8.out.h"
static LSym*
zsym(char *pn, Biobuf *f, LSym *h[])
{
int o;
o = BGETC(f);
if(o < 0 || o >= NSYM || h[o] == nil)
mangle(pn);
return h[o];
}
static void finish(Link*);
static void
zaddr(Link *ctxt, char *pn, Biobuf *f, Addr *a, LSym *h[], LSym **pgotype)
{
int t;
int32 l;
LSym *s, *gotype;
Auto *u;
uint64 v;
t = BGETC(f);
a->index = D_NONE;
a->scale = 0;
if(t & T_INDEX) {
a->index = BGETC(f);
a->scale = BGETC(f);
}
a->type = D_NONE;
a->offset = 0;
if(t & T_OFFSET)
a->offset = BGETLE4(f);
a->offset2 = 0;
if(t & T_OFFSET2) {
a->offset2 = BGETLE4(f);
a->type = D_CONST2;
}
a->sym = nil;
if(t & T_SYM)
a->sym = zsym(pn, f, h);
if(t & T_FCONST) {
v = (uint32)BGETLE4(f);
v |= (uint64)BGETLE4(f)<<32;
memmove(&a->u.dval, &v, 8);
a->type = D_FCONST;
} else
if(t & T_SCONST) {
Bread(f, a->u.sval, NSNAME);
a->type = D_SCONST;
}
if(t & T_TYPE)
a->type = BGETC(f);
gotype = nil;
if(t & T_GOTYPE)
gotype = zsym(pn, f, h);
if(pgotype)
*pgotype = gotype;
t = a->type;
if(t == D_INDIR+D_GS)
a->offset += ctxt->tlsoffset;
s = a->sym;
if(s == nil)
return;
if(t != D_AUTO && t != D_PARAM) {
if(gotype)
s->gotype = gotype;
return;
}
l = a->offset;
for(u=ctxt->curauto; u; u=u->link) {
if(u->asym == s)
if(u->type == t) {
if(u->aoffset > l)
u->aoffset = l;
if(gotype)
u->gotype = gotype;
return;
}
}
u = emallocz(sizeof(*u));
u->link = ctxt->curauto;
ctxt->curauto = u;
u->asym = s;
u->aoffset = l;
u->type = t;
u->gotype = gotype;
}
void
nopout8(Prog *p)
{
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
void
ldobj8(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
Prog *p;
int v, o, r, skip;
LSym *h[NSYM], *s;
uint32 sig;
int ntext;
int32 eof;
char *name, *x;
char src[1024], literal[64];
Prog *lastp;
LSym *fromgotype;
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
src[0] = 0;
pn = estrdup(pn); // we keep it in LSym* references
newloop:
memset(h, 0, sizeof(h));
ctxt->version++;
ctxt->histfrogp = 0;
ipc = ctxt->pc;
skip = 0;
loop:
if(f->state == Bracteof || Boffset(f) >= eof)
goto eof;
o = BGETC(f);
if(o == Beof)
goto eof;
o |= BGETC(f) << 8;
if(o <= AXXX || o >= ALAST) {
if(o < 0)
goto eof;
ctxt->diag("%s:#%lld: opcode out of range: %#ux", pn, Boffset(f), o);
print(" probably not a .%c file\n", ctxt->thechar);
sysfatal("invalid file");
}
if(o == ANAME || o == ASIGNAME) {
sig = 0;
if(o == ASIGNAME)
sig = BGETLE4(f);
USED(sig);
v = BGETC(f); /* type */
o = BGETC(f); /* sym */
r = 0;
if(v == D_STATIC)
r = ctxt->version;
name = Brdline(f, '\0');
if(name == nil) {
if(Blinelen(f) > 0)
sysfatal("%s: name too long", pn);
goto eof;
}
x = expandpkg(name, pkg);
s = linklookup(ctxt, x, r);
if(x != name)
free(x);
if(ctxt->debugread)
print(" ANAME %s\n", s->name);
if(o < 0 || o >= nelem(h))
mangle(pn);
h[o] = s;
if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
s->type = SXREF;
if(v == D_FILE) {
if(s->type != SFILE) {
ctxt->histgen++;
s->type = SFILE;
s->value = ctxt->histgen;
}
if(ctxt->histfrogp < LinkMaxHist) {
ctxt->histfrog[ctxt->histfrogp] = s;
ctxt->histfrogp++;
} else
collapsefrog(ctxt, s);
ctxt->dwarfaddfrag(s->value, s->name);
}
goto loop;
}
p = emallocz(sizeof(*p));
p->as = o;
p->lineno = BGETLE4(f);
p->back = 2;
zaddr(ctxt, pn, f, &p->from, h, &fromgotype);
zaddr(ctxt, pn, f, &p->to, h, nil);
if(ctxt->debugread)
print("%P\n", p);
switch(p->as) {
case AHISTORY:
if(p->to.offset == -1) {
addlib(ctxt, src, pn);
ctxt->histfrogp = 0;
goto loop;
}
if(src[0] == '\0')
copyhistfrog(ctxt, src, sizeof src);
addhist(ctxt, p->lineno, D_FILE); /* 'z' */
if(p->to.offset)
addhist(ctxt, p->to.offset, D_FILE1); /* 'Z' */
savehist(ctxt, p->lineno, p->to.offset);
ctxt->histfrogp = 0;
goto loop;
case AEND:
finish(ctxt);
if(Boffset(f) == eof)
return;
goto newloop;
case AGLOBL:
s = p->from.sym;
if(s->type == 0 || s->type == SXREF) {
s->type = SBSS;
s->size = 0;
}
if(s->type != SBSS && s->type != SNOPTRBSS && !s->dupok) {
ctxt->diag("%s: redefinition: %s in %s",
pn, s->name, ctxt->cursym ? ctxt->cursym->name : "<none>");
s->type = SBSS;
s->size = 0;
}
if(p->to.offset > s->size)
s->size = p->to.offset;
if(p->from.scale & DUPOK)
s->dupok = 1;
if(p->from.scale & RODATA)
s->type = SRODATA;
else if(p->from.scale & NOPTR)
s->type = SNOPTRBSS;
goto loop;
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(ctxt->debugvlog)
// Bprint(ctxt->bso, "skipping %s in %s: dupok\n", s->name, pn);
goto loop;
}
if(s->file == nil)
s->file = pn;
else if(s->file != pn) {
ctxt->diag("multiple initialization for %s: in both %s and %s", s->name, s->file, pn);
sysfatal("multiple init");
}
savedata(ctxt, s, p, pn);
free(p);
goto loop;
case AGOK:
ctxt->diag("%s: GOK opcode in %s", pn, ctxt->cursym ? ctxt->cursym->name : "<none>");
ctxt->pc++;
goto loop;
case ATYPE:
if(skip)
goto casdef;
ctxt->pc++;
goto loop;
case ATEXT:
s = p->from.sym;
if(s->text != nil) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: %s: redefinition", pn, s->name);
return;
}
if(ntext++ == 0 && s->type != 0 && s->type != SXREF) {
/* redefinition, so file has probably been seen before */
if(ctxt->debugvlog)
ctxt->diag("skipping: %s: redefinition: %s", pn, s->name);
return;
}
if(ctxt->cursym != nil && ctxt->cursym->text)
finish(ctxt);
skip = 0;
if(ctxt->etextp)
ctxt->etextp->next = s;
else
ctxt->textp = s;
ctxt->etextp = s;
s->text = p;
ctxt->cursym = s;
if(s->type != 0 && s->type != SXREF) {
if(p->from.scale & DUPOK) {
skip = 1;
goto casdef;
}
ctxt->diag("%s: redefinition: %s\n%P", pn, s->name, p);
}
s->type = STEXT;
s->hist = gethist(ctxt);
s->value = ctxt->pc;
s->args = p->to.offset2;
lastp = p;
p->pc = ctxt->pc++;
goto loop;
case AFMOVF:
case AFADDF:
case AFSUBF:
case AFSUBRF:
case AFMULF:
case AFDIVF:
case AFDIVRF:
case AFCOMF:
case AFCOMFP:
case AMOVSS:
case AADDSS:
case ASUBSS:
case AMULSS:
case ADIVSS:
case ACOMISS:
case AUCOMISS:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 9 max */
sprint(literal, "$(%.17gf)", (float32)p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
float32 f32;
int32 i32;
s->type = SRODATA;
f32 = p->from.u.dval;
memmove(&i32, &f32, 4);
adduint32(ctxt, s, i32);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
case AFMOVD:
case AFADDD:
case AFSUBD:
case AFSUBRD:
case AFMULD:
case AFDIVD:
case AFDIVRD:
case AFCOMD:
case AFCOMDP:
case AMOVSD:
case AADDSD:
case ASUBSD:
case AMULSD:
case ADIVSD:
case ACOMISD:
case AUCOMISD:
if(skip)
goto casdef;
if(p->from.type == D_FCONST) {
/* size sb 18 max */
sprint(literal, "$%.17g",
p->from.u.dval);
s = linklookup(ctxt, literal, 0);
if(s->type == 0) {
int64 i64;
s->type = SRODATA;
memmove(&i64, &p->from.u.dval, 8);
adduint64(ctxt, s, i64);
s->reachable = 0;
}
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.offset = 0;
}
goto casdef;
casdef:
default:
if(skip)
nopout8(p);
p->pc = ctxt->pc;
ctxt->pc++;
if(p->to.type == D_BRANCH)
p->to.offset += ipc;
if(lastp == nil) {
if(p->as != ANOP)
ctxt->diag("unexpected instruction: %P", p);
goto loop;
}
lastp->link = p;
lastp = p;
goto loop;
}
eof:
ctxt->diag("truncated object file: %s", pn);
}
static void
finish(Link *ctxt)
{
LSym *s;
histtoauto(ctxt);
if(ctxt->cursym != nil && ctxt->cursym->text) {
s = ctxt->cursym;
s->autom = ctxt->curauto;
// mkfwd(s);
// linkpatch(ctxt, s);
// ctxt->arch->follow(ctxt, s);
// ctxt->arch->addstacksplit(ctxt, s);
// ctxt->arch->assemble(ctxt, s);
// linkpcln(ctxt, s);
}
ctxt->curauto = 0;
ctxt->cursym = nil;
}

158
src/liblink/sym.c Normal file
View file

@ -0,0 +1,158 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <link.h>
static int
yy_isalpha(int c)
{
return c >= 0 && c <= 0xFF && isalpha(c);
}
Link*
linknew(LinkArch *arch)
{
Link *ctxt;
char *p;
char buf[1024];
nuxiinit();
ctxt = emallocz(sizeof *ctxt);
ctxt->arch = arch;
ctxt->version = HistVersion;
// TODO: Make caller pass in ctxt->arch,
// so that for example 6g only has the linkamd64 code.
p = getgoarch();
if(strncmp(p, arch->name, strlen(arch->name)) != 0)
sysfatal("invalid goarch %s (want %s or derivative)", p, arch->name);
if(getwd(buf, sizeof buf) == 0)
strcpy(buf, "/???");
if(yy_isalpha(buf[0]) && buf[1] == ':') {
// On Windows.
ctxt->windows = 1;
// Canonicalize path by converting \ to / (Windows accepts both).
for(p=buf; *p; p++)
if(*p == '\\')
*p = '/';
}
ctxt->pathname = strdup(buf);
return ctxt;
}
LSym*
linknewsym(Link *ctxt, char *symb, int v)
{
LSym *s;
int l;
l = strlen(symb) + 1;
s = malloc(sizeof(*s));
memset(s, 0, sizeof(*s));
s->dynid = -1;
s->plt = -1;
s->got = -1;
s->name = malloc(l + 1);
memmove(s->name, symb, l);
s->name[l] = '\0';
s->type = 0;
s->version = v;
s->value = 0;
s->sig = 0;
s->size = 0;
ctxt->nsymbol++;
s->allsym = ctxt->allsym;
ctxt->allsym = s;
return s;
}
static LSym*
_lookup(Link *ctxt, char *symb, int v, int creat)
{
LSym *s;
char *p;
uint32 h;
int c;
h = v;
for(p=symb; c = *p; p++)
h = h+h+h + c;
h &= 0xffffff;
h %= LINKHASH;
for(s = ctxt->hash[h]; s != nil; s = s->hash)
if(strcmp(s->name, symb) == 0)
return s;
if(!creat)
return nil;
s = linknewsym(ctxt, symb, v);
s->extname = s->name;
s->hash = ctxt->hash[h];
ctxt->hash[h] = s;
return s;
}
LSym*
linklookup(Link *ctxt, char *name, int v)
{
return _lookup(ctxt, name, v, 1);
}
// read-only lookup
LSym*
linkrlookup(Link *ctxt, char *name, int v)
{
return _lookup(ctxt, name, v, 0);
}
int
linksymfmt(Fmt *f)
{
LSym *s;
s = va_arg(f->args, LSym*);
if(s == nil)
return fmtstrcpy(f, "<nil>");
return fmtstrcpy(f, s->name);
}