Commit 2ec29312 authored by Russ Cox's avatar Russ Cox

liblink: make Prog, Addr more portable and document

Change-Id: Idda476b71ae23f7b73fe63f062cf3531c1268eb3
Reviewed-on: https://go-review.googlesource.com/3514Reviewed-by: 's avatarRob Pike <r@golang.org>
Reviewed-by: 's avatarAustin Clements <austin@google.com>
Reviewed-by: 's avatarAram Hăvărneanu <aram@mgk.ro>
Reviewed-by: 's avatarDave Cheney <dave@cheney.net>
parent a99369fd
......@@ -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)
//
// $<mem>
// Effective address of memory reference <mem>, 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 $<mem>, 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
//
// *<mem>
// Indirect reference through memory reference <mem>, 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.
//
// $*$<mem>
// No longer used.
// On machines with actual SB registers, $*$<mem> forced the
// instruction encoding to use a full 32-bit constant, never a
// reference relative to SB.
//
// $<floating point literal>
// Floating point constant value.
// Encoding:
// type = TYPE_FCONST
// u.dval = floating point value
//
// $<string literal, up to 8 chars>
// String literal value (raw bytes used for DATA instruction).
// Encoding:
// type = TYPE_SCONST
// u.sval = string
//
// <register name>
// 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, 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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment