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