mirror of
https://github.com/golang/go.git
synced 2026-05-08 19:40:35 +00:00
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:
parent
8642cbd660
commit
7d507dc6e6
67 changed files with 17385 additions and 17705 deletions
567
include/link.h
Normal file
567
include/link.h
Normal 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;
|
||||
|
|
@ -188,6 +188,8 @@ typedef u32int uint32;
|
|||
typedef s64int int64;
|
||||
typedef u64int uint64;
|
||||
|
||||
typedef float float32;
|
||||
typedef double float64;
|
||||
|
||||
#undef _NEEDUCHAR
|
||||
#undef _NEEDUSHORT
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
1491
src/cmd/5l/asm.c
1491
src/cmd/5l/asm.c
File diff suppressed because it is too large
Load diff
350
src/cmd/5l/l.h
350
src/cmd/5l/l.h
|
|
@ -31,6 +31,7 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <bio.h>
|
||||
#include <link.h>
|
||||
#include "5.out.h"
|
||||
|
||||
enum
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
724
src/cmd/5l/obj.c
724
src/cmd/5l/obj.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
234
src/cmd/6l/asm.c
234
src/cmd/6l/asm.c
|
|
@ -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;
|
||||
|
|
|
|||
365
src/cmd/6l/l.h
365
src/cmd/6l/l.h
|
|
@ -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*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
670
src/cmd/6l/obj.c
670
src/cmd/6l/obj.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
1372
src/cmd/6l/optab.c
1372
src/cmd/6l/optab.c
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1846
src/cmd/6l/span.c
1846
src/cmd/6l/span.c
File diff suppressed because it is too large
Load diff
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
|||
343
src/cmd/8l/asm.c
343
src/cmd/8l/asm.c
|
|
@ -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;
|
||||
|
|
|
|||
331
src/cmd/8l/l.h
331
src/cmd/8l/l.h
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
674
src/cmd/8l/obj.c
674
src/cmd/8l/obj.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
1032
src/cmd/8l/optab.c
1032
src/cmd/8l/optab.c
File diff suppressed because it is too large
Load diff
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1507
src/cmd/8l/span.c
1507
src/cmd/8l/span.c
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
184
src/cmd/ld/elf.c
184
src/cmd/ld/elf.c
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
1316
src/cmd/ld/lib.c
1316
src/cmd/ld/lib.c
File diff suppressed because it is too large
Load diff
387
src/cmd/ld/lib.h
387
src/cmd/ld/lib.h
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
104
src/cmd/ld/pass.c
Normal 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
258
src/cmd/ld/pcln.c
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
223
src/cmd/ld/pobj.c
Normal 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();
|
||||
}
|
||||
|
|
@ -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
5
src/liblink/Makefile
Normal 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
2443
src/liblink/asm5.c
Normal file
File diff suppressed because it is too large
Load diff
3289
src/liblink/asm6.c
Normal file
3289
src/liblink/asm6.c
Normal file
File diff suppressed because it is too large
Load diff
2571
src/liblink/asm8.c
Normal file
2571
src/liblink/asm8.c
Normal file
File diff suppressed because it is too large
Load diff
366
src/liblink/data.c
Normal file
366
src/liblink/data.c
Normal 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
74
src/liblink/go.c
Normal 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
572
src/liblink/ld.c
Normal 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
403
src/liblink/obj.c
Normal 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
1187
src/liblink/obj5.c
Normal file
File diff suppressed because it is too large
Load diff
1078
src/liblink/obj6.c
Normal file
1078
src/liblink/obj6.c
Normal file
File diff suppressed because it is too large
Load diff
937
src/liblink/obj8.c
Normal file
937
src/liblink/obj8.c
Normal 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
115
src/liblink/pass.c
Normal 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
298
src/liblink/pcln.c
Normal 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
585
src/liblink/rdobj5.c
Normal 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
495
src/liblink/rdobj6.c
Normal 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
466
src/liblink/rdobj8.c
Normal 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
158
src/liblink/sym.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue