]> Cypherpunks.ru repositories - gostls13.git/blobdiff - include/link.h
[dev.cc] all: merge master (b8fcae0) into dev.cc
[gostls13.git] / include / link.h
index 5dffe7bc6435516eda14ab541b93386bc9218735..bc0a96026a8f940c59193c69f4a49e11246775c2 100644 (file)
@@ -43,32 +43,156 @@ 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.
+//             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.
+//             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
+               uint64  bits; // raw union bits, for testing if anything has been written to any field
        } 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
-       struct Node*    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 +208,8 @@ struct       Reloc
        LSym*   xsym;
 };
 
+// TODO(rsc): Describe prog.
+// TODO(rsc): Describe TEXT/GLOBL flag in from3, DATA width in from3.
 struct Prog
 {
        vlong   pc;
@@ -94,33 +220,62 @@ 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)
+       Addr    from3; // addl source argument (e.g., RLWM/FMADD from, reg, from3, to)
        Addr    to;
        
        // 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
        uchar   printed;
 
        char    width;  /* fake for DATA */
        char    mode;   /* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
+};
+
+extern Prog zprog; // zeroed Prog
+
+// Prog.as opcodes.
+// These are the portable opcodes, common to all architectures.
+// Each architecture defines many more arch-specific opcodes,
+// with values starting at A_ARCHSPECIFIC.
+enum {
+       AXXX = 0,
+
+       ACALL,
+       ACHECKNIL,
+       ADATA,
+       ADUFFCOPY,
+       ADUFFZERO,
+       AEND,
+       AFUNCDATA,
+       AGLOBL,
+       AJMP,
+       ANOP,
+       APCDATA,
+       ARET,
+       ATEXT,
+       ATYPE,
+       AUNDEF,
+       AUSEFIELD,
+       AVARDEF,
+       AVARKILL,
        
-       /*c2go uchar TEXTFLAG; */
+       A_ARCHSPECIFIC, // first architecture-specific opcode value
 };
 
 // prevent incompatible type signatures between liblink and 8l on Plan 9
@@ -275,7 +430,7 @@ enum
        RV_TYPE_MASK = (RV_CHECK_OVERFLOW - 1),
 };
 
-// Auto.type
+// Auto.name
 enum
 {
        A_AUTO = 1,
@@ -287,7 +442,7 @@ struct      Auto
        LSym*   asym;
        Auto*   link;
        int32   aoffset;
-       int16   type;
+       int16   name;
        LSym*   gotype;
 };
 
@@ -472,47 +627,14 @@ 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*);
-       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     D_OREG;
-
-       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 */
@@ -589,6 +711,11 @@ void*      emallocz(long n);
 void*  erealloc(void *p, long n);
 char*  estrdup(char *p);
 char*  expandpkg(char *t0, char *pkg);
+void   linksetexp(void);
+char*  expstring(void);
+
+extern int     fieldtrack_enabled;
+extern int     framepointer_enabled;
 
 // ld.c
 void   addhist(Link *ctxt, int32 line, int type);
@@ -659,6 +786,9 @@ extern      LinkArch        linkarm;
 extern LinkArch        linkppc64;
 extern LinkArch        linkppc64le;
 
+extern int     linkbasepointer;
+extern void    linksetexp(void);
+
 #pragma        varargck        type    "A"     int
 #pragma        varargck        type    "E"     uint
 #pragma        varargck        type    "D"     Addr*