mirror of
https://github.com/golang/go
synced 2024-11-24 09:30:07 -07:00
d9c9665f1d
The USEFIELD instructions no longer make it to the linker, so we have to do something else to pin the references they were pinning. Emit a 0-length relocation of type R_USEFIELD. Fixes #7486. LGTM=iant R=golang-codereviews, iant CC=golang-codereviews, r https://golang.org/cl/95530043
617 lines
13 KiB
C
617 lines
13 KiB
C
// 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 Link Link;
|
|
typedef struct Plist Plist;
|
|
typedef struct LinkArch LinkArch;
|
|
typedef struct Library Library;
|
|
|
|
typedef struct Pcln Pcln;
|
|
typedef struct Pcdata Pcdata;
|
|
typedef struct Pciter Pciter;
|
|
|
|
// prevent incompatible type signatures between liblink and 8l on Plan 9
|
|
#pragma incomplete struct Node
|
|
|
|
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
|
|
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
|
|
uchar isize; // 6l, 8l
|
|
|
|
char width; /* fake for DATA */
|
|
char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
|
|
};
|
|
|
|
// prevent incompatible type signatures between liblink and 8l on Plan 9
|
|
#pragma incomplete struct Section
|
|
|
|
struct LSym
|
|
{
|
|
char* name;
|
|
char* extname; // name used in external object files
|
|
short type;
|
|
short version;
|
|
uchar dupok;
|
|
uchar external;
|
|
uchar nosplit;
|
|
uchar reachable;
|
|
uchar cgoexport;
|
|
uchar special;
|
|
uchar stkcheck;
|
|
uchar hide;
|
|
uchar leaf; // arm only
|
|
uchar fnptr; // arm only
|
|
uchar seenglobl;
|
|
uchar onlist; // on the textp or datap lists
|
|
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;
|
|
|
|
// STEXT
|
|
Auto* autom;
|
|
Prog* text;
|
|
Prog* etext;
|
|
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
|
|
};
|
|
|
|
// Reloc.type
|
|
enum
|
|
{
|
|
R_ADDR = 1,
|
|
R_SIZE,
|
|
R_CALL, // relocation for direct PC-relative call
|
|
R_CALLARM, // relocation for ARM direct call
|
|
R_CALLIND, // marker for indirect call (no actual relocating necessary)
|
|
R_CONST,
|
|
R_PCREL,
|
|
R_TLS,
|
|
R_TLS_LE, // TLS local exec offset from TLS segment register
|
|
R_TLS_IE, // TLS initial exec offset from TLS base pointer
|
|
R_GOTOFF,
|
|
R_PLT0,
|
|
R_PLT1,
|
|
R_PLT2,
|
|
R_USEFIELD,
|
|
};
|
|
|
|
// Auto.type
|
|
enum
|
|
{
|
|
A_AUTO = 1,
|
|
A_PARAM,
|
|
};
|
|
|
|
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;
|
|
};
|
|
|
|
// Pcdata iterator.
|
|
// for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
|
|
struct Pciter
|
|
{
|
|
Pcdata d;
|
|
uchar *p;
|
|
uint32 pc;
|
|
uint32 nextpc;
|
|
uint32 pcscale;
|
|
int32 value;
|
|
int start;
|
|
int done;
|
|
};
|
|
|
|
void pciterinit(Link*, Pciter*, Pcdata*);
|
|
void pciternext(Pciter*);
|
|
|
|
// 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;
|
|
|
|
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;
|
|
char* trimpath;
|
|
char* goroot;
|
|
char* goroot_final;
|
|
|
|
// 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[20];
|
|
LSym* gmsym;
|
|
LSym* plan9tos;
|
|
Prog* curp;
|
|
Prog* printp;
|
|
Prog* blitrl;
|
|
Prog* elitrl;
|
|
int rexflag;
|
|
int rep; // for nacl
|
|
int repn; // for nacl
|
|
int lock; // for nacl
|
|
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*, ...);
|
|
int mode;
|
|
Auto* curauto;
|
|
Auto* curhist;
|
|
LSym* cursym;
|
|
int version;
|
|
LSym* textp;
|
|
LSym* etextp;
|
|
int32 histdepth;
|
|
int32 nhistfile;
|
|
LSym* filesyms;
|
|
};
|
|
|
|
// LinkArch is the definition of a single architecture.
|
|
struct LinkArch
|
|
{
|
|
char* name; // "arm", "amd64", and so on
|
|
int thechar; // '5', '6', and so on
|
|
|
|
void (*addstacksplit)(Link*, LSym*);
|
|
void (*assemble)(Link*, LSym*);
|
|
int (*datasize)(Prog*);
|
|
void (*follow)(Link*, LSym*);
|
|
int (*iscall)(Prog*);
|
|
int (*isdata)(Prog*);
|
|
Prog* (*prg)(void);
|
|
void (*progedit)(Link*, Prog*);
|
|
void (*settextflag)(Prog*, int);
|
|
int (*symtype)(Addr*);
|
|
int (*textflag)(Prog*);
|
|
|
|
int minlc;
|
|
int ptrsize;
|
|
int regsize;
|
|
|
|
// TODO: Give these the same values on all systems.
|
|
int D_ADDR;
|
|
int D_AUTO;
|
|
int D_BRANCH;
|
|
int D_CONST;
|
|
int D_EXTERN;
|
|
int D_FCONST;
|
|
int D_NONE;
|
|
int D_PARAM;
|
|
int D_SCONST;
|
|
int D_STATIC;
|
|
|
|
int ACALL;
|
|
int ADATA;
|
|
int AEND;
|
|
int AFUNCDATA;
|
|
int AGLOBL;
|
|
int AJMP;
|
|
int ANOP;
|
|
int APCDATA;
|
|
int ARET;
|
|
int ATEXT;
|
|
int ATYPE;
|
|
int AUSEFIELD;
|
|
};
|
|
|
|
/* executable header types */
|
|
enum {
|
|
Hunknown = 0,
|
|
Hdarwin,
|
|
Hdragonfly,
|
|
Helf,
|
|
Hfreebsd,
|
|
Hlinux,
|
|
Hnacl,
|
|
Hnetbsd,
|
|
Hopenbsd,
|
|
Hplan9,
|
|
Hsolaris,
|
|
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);
|
|
int chipfloat5(Link *ctxt, float64 e);
|
|
int chipzero5(Link *ctxt, float64 e);
|
|
|
|
// 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, vlong siz);
|
|
|
|
// go.c
|
|
void double2ieee(uint64 *ieee, double native);
|
|
void* emallocz(long n);
|
|
void* erealloc(void *p, long n);
|
|
char* estrdup(char *p);
|
|
char* expandpkg(char *t0, char *pkg);
|
|
|
|
// ld.c
|
|
void addhist(Link *ctxt, int32 line, int type);
|
|
void addlib(Link *ctxt, char *src, char *obj, char *path);
|
|
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);
|
|
void linkgetline(Link *ctxt, 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*);
|
|
|
|
// list[568].c
|
|
void listinit5(void);
|
|
void listinit6(void);
|
|
void listinit8(void);
|
|
|
|
// obj.c
|
|
int linklinefmt(Link *ctxt, Fmt *fp);
|
|
void linklinehist(Link *ctxt, int lineno, char *f, int offset);
|
|
Plist* linknewplist(Link *ctxt);
|
|
void linkprfile(Link *ctxt, int32 l);
|
|
|
|
// objfile.c
|
|
void ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path);
|
|
void writeobj(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*);
|
|
|
|
// 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);
|
|
int headtype(char*);
|
|
char* headstr(int);
|
|
|
|
extern char* anames5[];
|
|
extern char* anames6[];
|
|
extern char* anames8[];
|
|
|
|
extern LinkArch link386;
|
|
extern LinkArch linkamd64;
|
|
extern LinkArch linkamd64p32;
|
|
extern LinkArch linkarm;
|
|
|
|
#pragma varargck type "A" int
|
|
#pragma varargck type "D" Addr*
|
|
#pragma varargck type "lD" Addr*
|
|
#pragma varargck type "P" Prog*
|
|
#pragma varargck type "R" int
|
|
|
|
// TODO(ality): remove this workaround.
|
|
// It's here because Pconv in liblink/list?.c references %L.
|
|
#pragma varargck type "L" int32
|