diff --git a/include/link.h b/include/link.h index 7653ad27860..42071dbb35f 100644 --- a/include/link.h +++ b/include/link.h @@ -43,32 +43,157 @@ 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 - +// An Addr is an argument to an instruction. +// The general forms and their encodings are: +// +// sym±offset(symkind)(reg)(index*scale) +// Memory reference at address &sym(symkind) + offset + reg + index*scale. +// Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted. +// If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg). +// To force a parsing as index*scale, write (index*1). +// Encoding: +// type = TYPE_MEM +// name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE) +// sym = sym +// offset = ±offset +// reg = reg (REG_*) +// index = index (REG_*) +// scale = scale (1, 2, 4, 8) +// +// $ +// Effective address of memory reference , defined above. +// NOTE: Today, on arm and ppc64, type = TYPE_CONST instead. +// Encoding: same as memory reference, but type = TYPE_ADDR. +// +// $<±integer value> +// This is a special case of $, in which only ±offset is present. +// It has a separate type for easy recognition. +// NOTE: Today, on arm and ppc64, TYPE_CONST and TYPE_ADDR are merged into just TYPE_CONST. +// Encoding: +// type = TYPE_CONST +// offset = ±integer value +// +// * +// Indirect reference through memory reference , defined above. +// Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function +// pointer stored in the data word sym(SB), not a function named sym(SB). +// Encoding: same as above, but type = TYPE_INDIR. +// +// $*$ +// No longer used. +// On machines with actual SB registers, $*$ forced the +// instruction encoding to use a full 32-bit constant, never a +// reference relative to SB. +// +// $ +// Floating point constant value. +// Encoding: +// type = TYPE_FCONST +// u.dval = floating point value +// +// $ +// String literal value (raw bytes used for DATA instruction). +// Encoding: +// type = TYPE_SCONST +// u.sval = string +// +// +// Any register: integer, floating point, control, segment, and so on. +// If looking for specific register kind, must check type and reg value range. +// Encoding: +// type = TYPE_REG +// reg = reg (REG_*) +// +// x(PC) +// Encoding: +// type = TYPE_BRANCH +// u.branch = Prog* reference OR ELSE offset = target pc (branch takes priority) +// +// $±x-±y +// Final argument to TEXT, specifying local frame size x and argument size y. +// In this form, x and y are integer literals only, not arbitrary expressions. +// This avoids parsing ambiguities due to the use of - as a separator. +// The ± are optional. +// If the final argument to TEXT omits the -±y, the encoding should still +// use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown. +// Encoding: +// type = TYPE_TEXTSIZE +// offset = x +// u.argsize = y +// +// reg<>shift, reg->shift, reg@>shift +// Shifted register value, for ARM. +// In this form, reg must be a register and shift can be a register or an integer constant. +// Encoding: +// type = TYPE_SHIFT +// offset = (reg&15) | shifttype<<5 | count +// shifttype = 0, 1, 2, 3 for <<, >>, ->, @> +// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant. +// +// (reg, reg) +// A destination register pair. When used as the last argument of an instruction, +// this form makes clear that both registers are destinations. +// Encoding: +// type = TYPE_REGREG +// reg = first register +// offset = second register +// +// reg, reg +// TYPE_REGREG2, to be removed. +// struct Addr { - vlong offset; - + int16 type; // could be int8 + int16 reg; + int16 index; + int8 scale; + int8 name; + int64 offset; + LSym* sym; + union { char sval[8]; float64 dval; - Prog* branch; // for 5g, 6g, 8g, 9g + Prog* branch; + int32 argsize; // for 5l, 8l } u; - LSym* sym; + // gotype is the name of the Go type descriptor for sym. + // It cannot be set using assembly syntax. + // It is generated by the Go compiler for global declarations, + // to convey information about pointer locations to the back end + // and for use in generating debug information. LSym* gotype; - short type; - uint8 index; - int8 scale; - int8 reg; // for 5l, 9l; GPRs and FPRs both start at 0 - int8 name; // for 5l, 9l - int8 class; // for 5l, 9l - uint8 etype; // for 5g, 6g, 8g - int32 offset2; // for 5l, 8l - void* node; // for 5g, 6g, 8g - int64 width; // for 5g, 6g, 8g + + int8 class; // for internal use by liblink + uint8 etype; // for internal use by 5g, 6g, 8g + void* node; // for internal use by 5g, 6g, 8g + int64 width; // for internal use by 5g, 6g, 8g +}; + +enum { + NAME_NONE = 0, + NAME_EXTERN, + NAME_STATIC, + NAME_AUTO, + NAME_PARAM, +}; + +enum { + TYPE_NONE = 0, + TYPE_BRANCH = 5, // avoid accidental conflicts with NAME_* + TYPE_TEXTSIZE, + TYPE_MEM, + TYPE_CONST, + TYPE_FCONST, + TYPE_SCONST, + TYPE_REG, + TYPE_ADDR, + TYPE_SHIFT, + TYPE_REGREG, + TYPE_REGREG2, + TYPE_INDIR, }; struct Reloc @@ -84,6 +209,8 @@ struct Reloc LSym* xsym; }; +// TODO(rsc): Describe prog. +// TOOD(rsc): Make ARM scond == 0 mean C_SCOND_NONE. struct Prog { vlong pc; @@ -94,7 +221,7 @@ struct Prog // operands Addr from; - uchar reg; // arm, ppc64 only (e.g., ADD from, reg, to); + int16 reg; // arm, ppc64 only (e.g., ADD from, reg, to); // starts at 0 for both GPRs and FPRs; // also used for ADATA width on arm, ppc64 Addr from3; // ppc64 only (e.g., RLWM/FMADD from, reg, from3, to) @@ -103,18 +230,18 @@ struct Prog // for 5g, 6g, 8g internal use void* opt; - // for 5l, 6l, 8l internal use + // for liblink internal use Prog* forwd; Prog* pcond; - Prog* comefrom; // 6l, 8l - Prog* pcrel; // 5l + Prog* comefrom; // amd64, 386 + Prog* pcrel; // arm int32 spadj; uint16 mark; - uint16 optab; // 5l, 9l - uchar back; // 6l, 8l - uchar ft; /* 6l, 8l oclass cache */ - uchar tt; // 6l, 8l - uchar isize; // 6l, 8l + uint16 optab; // arm, ppc64 + uchar back; // amd64, 386 + uchar ft; // oclass cache + uchar tt; // oclass cache + uchar isize; // amd64, 386 char width; /* fake for DATA */ char mode; /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */ @@ -273,7 +400,7 @@ enum RV_TYPE_MASK = (RV_CHECK_OVERFLOW - 1), }; -// Auto.type +// Auto.name enum { A_AUTO = 1, @@ -285,7 +412,7 @@ struct Auto LSym* asym; Auto* link; int32 aoffset; - int16 type; + int16 name; LSym* gotype; }; @@ -469,7 +596,7 @@ struct LinkArch int thechar; // '5', '6', and so on int32 endian; // LittleEndian or BigEndian - void (*addstacksplit)(Link*, LSym*); + void (*preprocess)(Link*, LSym*); void (*assemble)(Link*, LSym*); int (*datasize)(Prog*); void (*follow)(Link*, LSym*); @@ -478,26 +605,12 @@ struct LinkArch 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 D_OREG; - int ACALL; int ADATA; int AEND;