1: // Copyright (C) 1984-1998 by Symantec
   2: // Copyright (C) 2000-2011 by Digital Mars
   3: // All Rights Reserved
   4: // http://www.digitalmars.com
   5: // Written by Walter Bright
   6: /*
   7:  * This source file is made available for personal use
   8:  * only. The license is in /dmd/src/dmd/backendlicense.txt
   9:  * or /dm/src/dmd/backendlicense.txt
  10:  * For any other uses, please contact Digital Mars.
  11:  */
  12: 
  13: #if !SPP
  14: 
  15: #include        <stdio.h>
  16: #include        <string.h>
  17: #include        <stdlib.h>
  18: #include        <time.h>
  19: #include        "cc.h"
  20: #include        "el.h"
  21: #include        "code.h"
  22: #include        "oper.h"
  23: #include        "global.h"
  24: #include        "type.h"
  25: #include        "aa.h"
  26: #include        "tinfo.h"
  27: #if SCPP
  28: #include        "exh.h"
  29: #endif
  30: 
  31: #if HYDRATE
  32: #include        "parser.h"
  33: #endif
  34: 
  35: static char __file__[] = __FILE__;      /* for tassert.h                */
  36: #include        "tassert.h"
  37: 
  38: extern dt_t **dtnzeros(dt_t **pdtend,targ_size_t size);
  39: 
  40: extern targ_size_t retsize;
  41: STATIC void pinholeopt_unittest();
  42: STATIC void do8bit (enum FL,union evc *);
  43: STATIC void do16bit (enum FL,union evc *,int);
  44: STATIC void do32bit (enum FL,union evc *,int,targ_size_t = 0);
  45: STATIC void do64bit (enum FL,union evc *,int);
  46: 
  47: static int hasframe;            /* !=0 if this function has a stack frame */
  48: static targ_size_t Foff;        // BP offset of floating register
  49: static targ_size_t CSoff;       // offset of common sub expressions
  50: static targ_size_t NDPoff;      // offset of saved 8087 registers
  51: int BPoff;                      // offset from BP
  52: static int EBPtoESP;            // add to EBP offset to get ESP offset
  53: static int AAoff;               // offset of alloca temporary
  54: 
  55: #if ELFOBJ || MACHOBJ
  56: #define JMPSEG  CDATA
  57: #define JMPOFF  CDoffset
  58: #else
  59: #define JMPSEG  DATA
  60: #define JMPOFF  Doffset
  61: #endif
  62: 
  63: /************************
  64:  * When we don't know whether a function symbol is defined or not
  65:  * within this module, we stuff it in this linked list of references
  66:  * to be fixed up later.
  67:  */
  68: 
  69: struct fixlist
  70: {   //symbol      *Lsymbol;       // symbol we don't know about
  71:     int         Lseg;           // where the fixup is going (CODE or DATA, never UDATA)
  72:     int         Lflags;         // CFxxxx
  73:     targ_size_t Loffset;        // addr of reference to symbol
  74:     targ_size_t Lval;           // value to add into location
  75: #if TARGET_OSX
  76:     symbol      *Lfuncsym;      // function the symbol goes in
  77: #endif
  78:     fixlist *Lnext;             // next in threaded list
  79: 
  80:     static AArray *start;
  81:     static int nodel;           // don't delete from within searchfixlist
  82: };
  83: 
  84: AArray *fixlist::start = NULL;
  85: int fixlist::nodel = 0;
  86: 
  87: /*************
  88:  * Size in bytes of each instruction.
  89:  * 0 means illegal instruction.
  90:  * bit  M:      if there is a modregrm field (EV1 is reserved for modregrm)
  91:  * bit  T:      if there is a second operand (EV2)
  92:  * bit  E:      if second operand is only 8 bits
  93:  * bit  A:      a short version exists for the AX reg
  94:  * bit  R:      a short version exists for regs
  95:  * bits 2..0:   size of instruction (excluding optional bytes)
  96:  */
  97: 
  98: #define M 0x80
  99: #define T 0x40
 100: #define E 0x20
 101: #define A 0x10
 102: #define R 0x08
 103: #define W 0
 104: 
 105: static unsigned char inssize[256] =
 106: {       M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 00 */
 107:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 08 */
 108:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 10 */
 109:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 18 */
 110:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 20 */
 111:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 28 */
 112:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 30 */
 113:         M|2,M|2,M|2,M|2,        T|E|2,T|3,1,1,          /* 38 */
 114:         1,1,1,1,                1,1,1,1,                /* 40 */
 115:         1,1,1,1,                1,1,1,1,                /* 48 */
 116:         1,1,1,1,                1,1,1,1,                /* 50 */
 117:         1,1,1,1,                1,1,1,1,                /* 58 */
 118:         1,1,M|2,M|2,            1,1,1,1,                /* 60 */
 119:         T|3,M|T|4,T|E|2,M|T|E|3, 1,1,1,1,               /* 68 */
 120:         T|E|2,T|E|2,T|E|2,T|E|2, T|E|2,T|E|2,T|E|2,T|E|2,       /* 70 */
 121:         T|E|2,T|E|2,T|E|2,T|E|2, T|E|2,T|E|2,T|E|2,T|E|2,       /* 78 */
 122:         M|T|E|A|3,M|T|A|4,M|T|E|3,M|T|E|3,      M|2,M|2,M|2,M|A|R|2, /* 80 */
 123:         M|A|2,M|A|2,M|A|2,M|A|2,        M|2,M|2,M|2,M|R|2,      /* 88 */
 124:         1,1,1,1,                1,1,1,1,                /* 90 */
 125:         1,1,T|5,1,              1,1,1,1,                /* 98 */
 126: #if 0 /* cod3_set32() patches this */
 127:         T|5,T|5,T|5,T|5,        1,1,1,1,                /* A0 */
 128: #else
 129:         T|3,T|3,T|3,T|3,        1,1,1,1,                /* A0 */
 130: #endif
 131:         T|E|2,T|3,1,1,          1,1,1,1,                /* A8 */
 132:         T|E|2,T|E|2,T|E|2,T|E|2, T|E|2,T|E|2,T|E|2,T|E|2,       /* B0 */
 133:         T|3,T|3,T|3,T|3,        T|3,T|3,T|3,T|3,                /* B8 */
 134:         M|T|E|3,M|T|E|3,T|3,1,  M|2,M|2,M|T|E|R|3,M|T|R|4,      /* C0 */
 135:         T|E|4,1,T|3,1,          1,T|E|2,1,1,            /* C8 */
 136:         M|2,M|2,M|2,M|2,        T|E|2,T|E|2,0,1,        /* D0 */
 137:         /* For the floating instructions, allow room for the FWAIT      */
 138:         M|2,M|2,M|2,M|2,        M|2,M|2,M|2,M|2,        /* D8 */
 139:         T|E|2,T|E|2,T|E|2,T|E|2, T|E|2,T|E|2,T|E|2,T|E|2,       /* E0 */
 140:         T|3,T|3,T|5,T|E|2,              1,1,1,1,                /* E8 */
 141:         1,0,1,1,                1,1,M|A|2,M|A|2,                /* F0 */
 142:         1,1,1,1,                1,1,M|2,M|R|2                   /* F8 */
 143: };
 144: 
 145: static const unsigned char inssize32[256] =
 146: {       2,2,2,2,        2,5,1,1,                /* 00 */
 147:         2,2,2,2,        2,5,1,1,                /* 08 */
 148:         2,2,2,2,        2,5,1,1,                /* 10 */
 149:         2,2,2,2,        2,5,1,1,                /* 18 */
 150:         2,2,2,2,        2,5,1,1,                /* 20 */
 151:         2,2,2,2,        2,5,1,1,                /* 28 */
 152:         2,2,2,2,        2,5,1,1,                /* 30 */
 153:         2,2,2,2,        2,5,1,1,                /* 38 */
 154:         1,1,1,1,        1,1,1,1,                /* 40 */
 155:         1,1,1,1,        1,1,1,1,                /* 48 */
 156:         1,1,1,1,        1,1,1,1,                /* 50 */
 157:         1,1,1,1,        1,1,1,1,                /* 58 */
 158:         1,1,2,2,        1,1,1,1,                /* 60 */
 159:         5,6,2,3,        1,1,1,1,                /* 68 */
 160:         2,2,2,2,        2,2,2,2,                /* 70 */
 161:         2,2,2,2,        2,2,2,2,                /* 78 */
 162:         3,6,3,3,        2,2,2,2,                /* 80 */
 163:         2,2,2,2,        2,2,2,2,                /* 88 */
 164:         1,1,1,1,        1,1,1,1,                /* 90 */
 165:         1,1,7,1,        1,1,1,1,                /* 98 */
 166:         5,5,5,5,        1,1,1,1,                /* A0 */
 167:         2,5,1,1,        1,1,1,1,                /* A8 */
 168:         2,2,2,2,        2,2,2,2,                /* B0 */
 169:         5,5,5,5,        5,5,5,5,                /* B8 */
 170:         3,3,3,1,        2,2,3,6,                /* C0 */
 171:         4,1,3,1,        1,2,1,1,                /* C8 */
 172:         2,2,2,2,        2,2,0,1,                /* D0 */
 173:         /* For the floating instructions, don't need room for the FWAIT */
 174:         2,2,2,2,        2,2,2,2,                /* D8 */
 175: 
 176:         2,2,2,2,        2,2,2,2,                /* E0 */
 177:         5,5,7,2,        1,1,1,1,                /* E8 */
 178:         1,0,1,1,        1,1,2,2,                /* F0 */
 179:         1,1,1,1,        1,1,2,2                 /* F8 */
 180: };
 181: 
 182: /* For 2 byte opcodes starting with 0x0F        */
 183: static unsigned char inssize2[256] =
 184: {       M|3,M|3,M|3,M|3,        2,2,2,2,                // 00
 185:         2,2,M|3,2,              2,2,2,M|T|E|4,          // 08
 186:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 10
 187:         M|3,2,2,2,              2,2,2,2,                // 18
 188:         M|3,M|3,M|3,M|3,        M|3,2,M|3,2,            // 20
 189:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 28
 190:         2,2,2,2,                2,2,2,2,                // 30
 191:         M|4,2,M|T|E|5,2,        2,2,2,2,                // 38
 192:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 40
 193:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 48
 194:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 50
 195:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 58
 196:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 60
 197:         M|3,M|3,M|3,M|3,        M|3,M|3,M|3,M|3,        // 68
 198:         M|T|E|4,M|T|E|4,M|T|E|4,M|T|E|4, M|3,M|3,M|3,2, // 70
 199:         2,2,2,2,                M|3,M|3,M|3,M|3,        // 78
 200:         W|T|4,W|T|4,W|T|4,W|T|4, W|T|4,W|T|4,W|T|4,W|T|4, // 80
 201:         W|T|4,W|T|4,W|T|4,W|T|4, W|T|4,W|T|4,W|T|4,W|T|4, // 88
 202:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // 90
 203:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // 98
 204:         2,2,2,M|3,      M|T|E|4,M|3,2,2,        // A0
 205:         2,2,2,M|3,      M|T|E|4,M|3,M|3,M|3,    // A8
 206:         M|E|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,     // B0
 207:         M|3,2,M|T|E|4,M|3, M|3,M|3,M|3,M|3,     // B8
 208:         M|3,M|3,M|T|E|4,M|3, M|T|E|4,M|T|E|4,M|T|E|4,M|3,       // C0
 209:         2,2,2,2,        2,2,2,2,                // C8
 210:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // D0
 211:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // D8
 212:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // E0
 213:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // E8
 214:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,M|3,       // F0
 215:         M|3,M|3,M|3,M|3, M|3,M|3,M|3,2          // F8
 216: };
 217: 
 218: /************************************
 219:  * Determine if there is a modregrm byte for code.
 220:  */
 221: 
 222: int cod3_EA(code *c)
 223: {   unsigned ins;
 224: 
 225:     unsigned op1 = c->Iop & 0xFF;
 226:     if (op1 == ESCAPE)
 227:         ins = 0;
 228:     else if ((c->Iop & 0xFFFD00) == 0x0F3800)
 229:         ins = inssize2[(c->Iop >> 8) & 0xFF];
 230:     else if ((c->Iop & 0xFF00) == 0x0F00)
 231:         ins = inssize2[op1];
 232:     else
 233:         ins = inssize[op1];
 234:     return ins & M;
 235: }
 236: 
 237: /********************************
 238:  * Fix global variables for 386.
 239:  */
 240: 
 241: void cod3_set32()
 242: {
 243:     inssize[0xA0] = T|5;
 244:     inssize[0xA1] = T|5;
 245:     inssize[0xA2] = T|5;
 246:     inssize[0xA3] = T|5;
 247:     BPRM = 5;                       /* [EBP] addressing mode        */
 248:     fregsaved = mBP | mBX | mSI | mDI;      // saved across function calls
 249:     FLOATREGS = FLOATREGS_32;
 250:     FLOATREGS2 = FLOATREGS2_32;
 251:     DOUBLEREGS = DOUBLEREGS_32;
 252:     if (config.flags3 & CFG3eseqds)
 253:         fregsaved |= mES;
 254: 
 255:     for (unsigned i = 0x80; i < 0x90; i++)
 256:         inssize2[i] = W|T|6;
 257: }
 258: 
 259: /********************************
 260:  * Fix global variables for I64.
 261:  */
 262: 
 263: void cod3_set64()
 264: {
 265:     inssize[0xA0] = T|5;                // MOV AL,mem
 266:     inssize[0xA1] = T|5;                // MOV RAX,mem
 267:     inssize[0xA2] = T|5;                // MOV mem,AL
 268:     inssize[0xA3] = T|5;                // MOV mem,RAX
 269:     BPRM = 5;                           // [RBP] addressing mode
 270: 
 271:     fregsaved = mBP | mBX | mR12 | mR13 | mR14 | mR15 | mES;      // saved across function calls
 272:     FLOATREGS = FLOATREGS_64;
 273:     FLOATREGS2 = FLOATREGS2_64;
 274:     DOUBLEREGS = DOUBLEREGS_64;
 275:     STACKALIGN = 16;
 276: 
 277: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
 278:     ALLREGS = mAX|mBX|mCX|mDX|mSI|mDI|  mR8|mR9|mR10|mR11|mR12|mR13|mR14|mR15;
 279:     BYTEREGS = ALLREGS;
 280: #endif
 281: 
 282:     for (unsigned i = 0x80; i < 0x90; i++)
 283:         inssize2[i] = W|T|6;
 284: }
 285: 
 286: /*********************************
 287:  * Word or dword align start of function.
 288:  */
 289: 
 290: void cod3_align()
 291: {
 292:     static char nops[7] = { 0x90,0x90,0x90,0x90,0x90,0x90,0x90 };
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
293: unsigned nbytes; 294: #if OMFOBJ 295: if (config.flags4 & CFG4speed) // if optimized for speed 296: { 297: // Pick alignment based on CPU target 298: if (config.target_cpu == TARGET_80486 || 299: config.target_cpu >= TARGET_PentiumPro) 300: { // 486 does reads on 16 byte boundaries, so if we are near 301: // such a boundary, align us to it 302: 303: nbytes = -Coffset & 15;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
304: if (nbytes < 8) 305: { 306: Coffset += obj_bytes(cseg,Coffset,nbytes,nops); // XCHG AX,AX 307: } 308: } 309: } 310: #else 311: nbytes = -Coffset & 3; 312: //dbg_printf("cod3_align Coffset %x nbytes %d\n",Coffset,nbytes); 313: obj_bytes(cseg,Coffset,nbytes,nops); 314: #endif 315: } 316: 317: /******************************* 318: * Generate code for blocks ending in a switch statement. 319: * Take BCswitch and decide on 320: * BCifthen use if - then code 321: * BCjmptab index into jump table 322: * BCswitch search table for match 323: */ 324: 325: void doswitch(block *b) 326: { code *cc,*c,*ce; 327: regm_t retregs; 328: unsigned ncases,n,reg,reg2,rm; 329: targ_llong vmax,vmin,val; 330: targ_llong *p; 331: list_t bl; 332: elem *e; 333: 334: tym_t tys; 335: int sz; 336: unsigned char dword; 337: unsigned char mswsame; 338: #if LONGLONG 339: targ_ulong msw; 340: #else 341: unsigned msw; 342: #endif 343: 344: e = b->Belem; 345: elem_debug(e); 346: cc = docommas(&e); 347: cgstate.stackclean++; 348: tys = tybasic(e->Ety); 349: sz = tysize[tys]; 350: dword = (sz == 2 * REGSIZE); 351: mswsame = 1; // assume all msw's are the same 352: p = b->BS.Bswitch; /* pointer to case data */ 353: assert(p); 354: ncases = *p++; /* number of cases */
warning C4244: '=' : conversion from 'targ_llong' to 'unsigned int', possible loss of data
355: 356: vmax = MINLL; // smallest possible llong 357: vmin = MAXLL; // largest possible llong 358: for (n = 0; n < ncases; n++) // find max and min case values 359: { val = *p++; 360: if (val > vmax) vmax = val; 361: if (val < vmin) vmin = val; 362: if (REGSIZE == 2) 363: { 364: unsigned short ms = (val >> 16) & 0xFFFF; 365: if (n == 0) 366: msw = ms; 367: else if (msw != ms) 368: mswsame = 0; 369: } 370: else // REGSIZE == 4 371: { 372: targ_ulong ms = (val >> 32) & 0xFFFFFFFF; 373: if (n == 0) 374: msw = ms; 375: else if (msw != ms) 376: mswsame = 0; 377: } 378: } 379: p -= ncases; 380: //dbg_printf("vmax = x%lx, vmin = x%lx, vmax-vmin = x%lx\n",vmax,vmin,vmax - vmin); 381: 382: if (I64) 383: { // For now, just generate basic if-then sequence to get us running 384: retregs = ALLREGS; 385: b->BC = BCifthen; 386: c = scodelem(e,&retregs,0,TRUE); 387: assert(!dword); // 128 bit switches not supported 388: reg = findreg(retregs); // reg that result is in 389: bl = b->Bsucc; 390: for (n = 0; n < ncases; n++) 391: { code *cx; 392: val = *p; 393: if (sz == 4) 394: cx = genc2(CNIL,0x81,modregrmx(3,7,reg),val); // CMP reg,val
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
395: else if (sz == 8) 396: { 397: if (val == (int)val) // if val is a 64 bit value sign-extended from 32 bits 398: { 399: cx = genc2(CNIL,0x81,modregrmx(3,7,reg),val); // CMP reg,value32
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
400: cx->Irex |= REX_W; // 64 bit operand 401: } 402: else 403: { unsigned sreg; 404: // MOV sreg,value64 405: cx = regwithvalue(CNIL, ALLREGS & ~mask[reg], val, &sreg, 64);
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
406: cx = genregs(cx,0x3B,reg,sreg); // CMP reg,sreg 407: code_orrex(cx, REX_W); 408: } 409: } 410: else 411: assert(0); 412: bl = list_next(bl); 413: genjmp(cx,JE,FLblock,list_block(bl)); // JE caseaddr 414: c = cat(c,cx); 415: p++; 416: } 417: if (list_block(b->Bsucc) != b->Bnext) /* if default is not next block */ 418: c = cat(c,genjmp(CNIL,JMP,FLblock,list_block(b->Bsucc))); 419: ce = NULL; 420: } 421: // Need to do research on MACHOBJ to see about better methods 422: else if (MACHOBJ || ncases <= 3) 423: { // generate if-then sequence 424: retregs = ALLREGS; 425: L1: 426: b->BC = BCifthen; 427: c = scodelem(e,&retregs,0,TRUE); 428: if (dword) 429: { reg = findreglsw(retregs); 430: reg2 = findregmsw(retregs); 431: } 432: else 433: reg = findreg(retregs); /* reg that result is in */ 434: bl = b->Bsucc; 435: if (dword && mswsame) 436: { /* CMP reg2,MSW */ 437: c = genc2(c,0x81,modregrm(3,7,reg2),msw);
warning C6001: Using uninitialized memory 'msw': Lines: 326, 327, 328, 329, 330, 331, 332, 334, 335, 336, 337, 339, 344, 346, 347, 348, 349, 350, 351, 352, 353, 354, 356, 357, 358, 379, 382, 422, 424, 425, 426, 427, 428, 429, 430, 434, 435, 437
438: genjmp(c,JNE,FLblock,list_block(b->Bsucc)); /* JNE default */ 439: } 440: for (n = 0; n < ncases; n++) 441: { code *cnext = CNIL; 442: /* CMP reg,casevalue */ 443: c = cat(c,ce = genc2(CNIL,0x81,modregrm(3,7,reg),(targ_int)*p)); 444: if (dword && !mswsame) 445: { 446: cnext = gennop(CNIL); 447: genjmp(ce,JNE,FLcode,(block *) cnext); 448: genc2(ce,0x81,modregrm(3,7,reg2),MSREG(*p));
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
449: } 450: bl = list_next(bl); 451: /* JE caseaddr */ 452: genjmp(ce,JE,FLblock,list_block(bl)); 453: c = cat(c,cnext); 454: p++; 455: } 456: if (list_block(b->Bsucc) != b->Bnext) /* if default is not next block */ 457: c = cat(c,genjmp(CNIL,JMP,FLblock,list_block(b->Bsucc))); 458: ce = NULL; 459: } 460: #if TARGET_WINDOS // try and find relocation to support this 461: else if ((targ_ullong)(vmax - vmin) <= ncases * 2) // then use jump table 462: { int modify; 463: 464: b->BC = BCjmptab; 465: retregs = IDXREGS; 466: if (dword) 467: retregs |= mMSW; 468: modify = (vmin || !I32); 469: c = scodelem(e,&retregs,0,!modify); 470: reg = findreg(retregs & IDXREGS); /* reg that result is in */ 471: if (dword) 472: reg2 = findregmsw(retregs); 473: if (modify) 474: { 475: assert(!(retregs & regcon.mvar)); 476: c = cat(c,getregs(retregs)); 477: } 478: if (vmin) /* if there is a minimum */ 479: { 480: c = genc2(c,0x81,modregrm(3,5,reg),vmin); /* SUB reg,vmin */
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
481: if (dword) 482: { genc2(c,0x81,modregrm(3,3,reg2),MSREG(vmin)); // SBB reg2,vmin
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
483: genjmp(c,JNE,FLblock,list_block(b->Bsucc)); /* JNE default */ 484: } 485: } 486: else if (dword) 487: { c = gentstreg(c,reg2); // TEST reg2,reg2 488: genjmp(c,JNE,FLblock,list_block(b->Bsucc)); /* JNE default */ 489: } 490: if (vmax - vmin != REGMASK) /* if there is a maximum */ 491: { /* CMP reg,vmax-vmin */ 492: c = genc2(c,0x81,modregrm(3,7,reg),vmax-vmin);
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
493: genjmp(c,JA,FLblock,list_block(b->Bsucc)); /* JA default */ 494: } 495: if (!I32) 496: c = gen2(c,0xD1,modregrm(3,4,reg)); /* SHL reg,1 */ 497: if (I32) 498: { 499: ce = genc1(CNIL,0xFF,modregrm(0,4,4),FLswitch,0); /* JMP [CS:]disp[idxreg*4] */ 500: ce->Isib = modregrm(2,reg,5); 501: } 502: else 503: { rm = getaddrmode(retregs) | modregrm(0,4,0); 504: ce = genc1(CNIL,0xFF,rm,FLswitch,0); /* JMP [CS:]disp[idxreg] */ 505: } 506: int flags = (config.flags & CFGromable) ? CFcs : 0; // table is in code seg 507: ce->Iflags |= flags; // segment override 508: ce->IEV1.Vswitch = b; 509: b->Btablesize = (int) (vmax - vmin + 1) * tysize[TYnptr]; 510: } 511: #endif 512: else /* else use switch table (BCswitch) */ 513: { targ_size_t disp; 514: int mod; 515: code *esw; 516: code *ct; 517: 518: retregs = mAX; /* SCASW requires AX */ 519: if (dword) 520: retregs |= mDX; 521: else if (ncases <= 6 || config.flags4 & CFG4speed) 522: goto L1; 523: c = scodelem(e,&retregs,0,TRUE); 524: if (dword && mswsame) 525: { /* CMP DX,MSW */ 526: c = genc2(c,0x81,modregrm(3,7,DX),msw); 527: genjmp(c,JNE,FLblock,list_block(b->Bsucc)); /* JNE default */ 528: } 529: ce = getregs(mCX|mDI); 530: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 531: if (config.flags3 & CFG3pic) 532: { // Add in GOT 533: code *cx; 534: code *cgot; 535: 536: ce = cat(ce, getregs(mDX)); 537: cx = genc2(NULL,CALL,0,0); // CALL L1 538: gen1(cx, 0x58 + DI); // L1: POP EDI 539: 540: // ADD EDI,_GLOBAL_OFFSET_TABLE_+3 541: symbol *gotsym = elfobj_getGOTsym(); 542: cgot = gencs(CNIL,0x81,modregrm(3,0,DI),FLextern,gotsym); 543: cgot->Iflags = CFoff; 544: cgot->IEVoffset2 = 3; 545: 546: makeitextern(gotsym); 547: 548: genmovreg(cgot, DX, DI); // MOV EDX, EDI 549: // ADD EDI,offset of switch table 550: esw = gencs(CNIL,0x81,modregrm(3,0,DI),FLswitch,NULL); 551: esw->IEV2.Vswitch = b; 552: esw = cat3(cx, cgot, esw); 553: } 554: else 555: #endif 556: { 557: // MOV DI,offset of switch table 558: esw = gencs(CNIL,0xC7,modregrm(3,0,DI),FLswitch,NULL); 559: esw->IEV2.Vswitch = b; 560: } 561: ce = cat(ce,esw); 562: movregconst(ce,CX,ncases,0); /* MOV CX,ncases */ 563: 564: /* The switch table will be accessed through ES:DI. 565: * Therefore, load ES with proper segment value. 566: */ 567: if (config.flags3 & CFG3eseqds) 568: { assert(!(config.flags & CFGromable)); 569: ce = cat(ce,getregs(mCX)); // allocate CX 570: } 571: else 572: { 573: ce = cat(ce,getregs(mES|mCX)); // allocate ES and CX 574: gen1(ce,(config.flags & CFGromable) ? 0x0E : 0x1E); // PUSH CS/DS 575: gen1(ce,0x07); // POP ES 576: } 577: 578: disp = (ncases - 1) * intsize; /* displacement to jump table */ 579: if (dword && !mswsame) 580: { code *cloop; 581: 582: /* Build the following: 583: L1: SCASW 584: JNE L2 585: CMP DX,[CS:]disp[DI] 586: L2: LOOPNE L1 587: */ 588: 589: mod = (disp > 127) ? 2 : 1; /* displacement size */ 590: cloop = genc2(CNIL,0xE0,0,-7 - mod - 591: ((config.flags & CFGromable) ? 1 : 0)); /* LOOPNE scasw */ 592: ce = gen1(ce,0xAF); /* SCASW */ 593: code_orflag(ce,CFtarg2); // target of jump 594: genjmp(ce,JNE,FLcode,(block *) cloop); /* JNE loop */ 595: /* CMP DX,[CS:]disp[DI] */ 596: ct = genc1(CNIL,0x39,modregrm(mod,DX,5),FLconst,disp); 597: int flags = (config.flags & CFGromable) ? CFcs : 0; // table is in code seg 598: ct->Iflags |= flags; // possible seg override 599: ce = cat3(ce,ct,cloop); 600: disp += ncases * intsize; /* skip over msw table */ 601: } 602: else 603: { 604: ce = gen1(ce,0xF2); /* REPNE */ 605: gen1(ce,0xAF); /* SCASW */ 606: } 607: genjmp(ce,JNE,FLblock,list_block(b->Bsucc)); /* JNE default */ 608: mod = (disp > 127) ? 2 : 1; /* 1 or 2 byte displacement */ 609: if (config.flags & CFGromable) 610: gen1(ce,SEGCS); /* table is in code segment */ 611: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 612: if (config.flags3 & CFG3pic) 613: { // ADD EDX,(ncases-1)*2[EDI] 614: ct = genc1(CNIL,0x03,modregrm(mod,DX,7),FLconst,disp); 615: // JMP EDX 616: gen2(ct,0xFF,modregrm(3,4,DX)); 617: } 618: else 619: #endif 620: { // JMP (ncases-1)*2[DI] 621: ct = genc1(CNIL,0xFF,modregrm(mod,4,(I32 ? 7 : 5)),FLconst,disp); 622: int flags = (config.flags & CFGromable) ? CFcs : 0; // table is in code seg 623: ct->Iflags |= flags; 624: } 625: ce = cat(ce,ct); 626: b->Btablesize = disp + intsize + ncases * tysize[TYnptr]; 627: } 628: b->Bcode = cat3(cc,c,ce); 629: //assert(b->Bcode); 630: cgstate.stackclean--; 631: } 632: 633: /****************************** 634: * Output data block for a jump table (BCjmptab). 635: * The 'holes' in the table get filled with the 636: * default label. 637: */ 638: 639: void outjmptab(block *b) 640: { 641: unsigned ncases,n; 642: targ_llong u,vmin,vmax,val,*p; 643: targ_size_t alignbytes,def,targ,*poffset; 644: int jmpseg; 645: 646: poffset = (config.flags & CFGromable) ? &Coffset : &JMPOFF; 647: p = b->BS.Bswitch; /* pointer to case data */ 648: ncases = *p++; /* number of cases */
warning C4244: '=' : conversion from 'targ_llong' to 'unsigned int', possible loss of data
649: vmax = MINLL; // smallest possible llong 650: vmin = MAXLL; // largest possible llong 651: for (n = 0; n < ncases; n++) /* find min case value */ 652: { val = p[n]; 653: if (val > vmax) vmax = val; 654: if (val < vmin) vmin = val; 655: } 656: jmpseg = (config.flags & CFGromable) ? cseg : JMPSEG; 657: 658: /* Any alignment bytes necessary */ 659: alignbytes = align(0,*poffset) - *poffset; 660: obj_lidata(jmpseg,*poffset,alignbytes); 661: #if OMFOBJ 662: *poffset += alignbytes; 663: #endif 664: 665: def = list_block(b->Bsucc)->Boffset; /* default address */ 666: assert(vmin <= vmax); 667: for (u = vmin; ; u++) 668: { targ = def; /* default */ 669: for (n = 0; n < ncases; n++) 670: { if (p[n] == u) 671: { targ = list_block(list_nth(b->Bsucc,n + 1))->Boffset; 672: break; 673: } 674: } 675: reftocodseg(jmpseg,*poffset,targ); 676: *poffset += tysize[TYnptr]; 677: if (u == vmax) /* for case that (vmax == ~0) */ 678: break; 679: } 680: } 681: 682: /****************************** 683: * Output data block for a switch table. 684: * Two consecutive tables, the first is the case value table, the 685: * second is the address table. 686: */ 687: 688: void outswitab(block *b) 689: { unsigned ncases,n; 690: targ_llong *p; 691: targ_size_t val; 692: targ_size_t alignbytes,*poffset; 693: int seg; /* target segment for table */ 694: list_t bl; 695: unsigned sz; 696: targ_size_t offset; 697: 698: //printf("outswitab()\n"); 699: p = b->BS.Bswitch; /* pointer to case data */ 700: ncases = *p++; /* number of cases */
warning C4244: '=' : conversion from 'targ_llong' to 'unsigned int', possible loss of data
701: 702: if (config.flags & CFGromable) 703: { poffset = &Coffset; 704: seg = cseg; 705: } 706: else 707: { 708: poffset = &JMPOFF; 709: seg = JMPSEG; 710: } 711: offset = *poffset; 712: alignbytes = align(0,*poffset) - *poffset; 713: //printf("\t*poffset = x%x, alignbytes = %d, intsize = %d\n", *poffset, alignbytes, intsize); 714: obj_lidata(seg,*poffset,alignbytes); /* any alignment bytes necessary */ 715: #if OMFOBJ 716: *poffset += alignbytes; 717: #endif 718: assert(*poffset == offset + alignbytes); 719: 720: sz = intsize; 721: for (n = 0; n < ncases; n++) /* send out value table */ 722: { 723: //printf("\tcase %d, offset = x%x\n", n, *poffset); 724: #if OMFOBJ 725: *poffset += 726: #endif 727: obj_bytes(seg,*poffset,sz,p); 728: p++; 729: } 730: offset += alignbytes + sz * ncases; 731: assert(*poffset == offset); 732: 733: if (b->Btablesize == ncases * (REGSIZE * 2 + tysize[TYnptr])) 734: { 735: /* Send out MSW table */ 736: p -= ncases; 737: for (n = 0; n < ncases; n++) 738: { val = MSREG(*p);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
739: p++; 740: #if OMFOBJ 741: *poffset += 742: #endif 743: obj_bytes(seg,*poffset,REGSIZE,&val); 744: } 745: offset += REGSIZE * ncases; 746: assert(*poffset == offset); 747: } 748: 749: bl = b->Bsucc; 750: for (n = 0; n < ncases; n++) /* send out address table */ 751: { bl = list_next(bl); 752: reftocodseg(seg,*poffset,list_block(bl)->Boffset); 753: *poffset += tysize[TYnptr]; 754: } 755: assert(*poffset == offset + ncases * tysize[TYnptr]); 756: } 757: 758: /***************************** 759: * Return a jump opcode relevant to the elem for a JMP TRUE. 760: */ 761: 762: int jmpopcode(elem *e) 763: { tym_t tym; 764: int zero,i,jp,op; 765: static const char jops[][2][6] = 766: { /* <= > < >= == != <=0 >0 <0 >=0 ==0 !=0 */ 767: { {JLE,JG ,JL ,JGE,JE ,JNE},{JLE,JG ,JS ,JNS,JE ,JNE} }, /* signed */ 768: { {JBE,JA ,JB ,JAE,JE ,JNE},{JE ,JNE,JB ,JAE,JE ,JNE} }, /* unsigned */ 769: #if 0 770: { {JLE,JG ,JL ,JGE,JE ,JNE},{JLE,JG ,JL ,JGE,JE ,JNE} }, /* real */ 771: { {JBE,JA ,JB ,JAE,JE ,JNE},{JBE,JA ,JB ,JAE,JE ,JNE} }, /* 8087 */ 772: { {JA ,JBE,JAE,JB ,JE ,JNE},{JBE,JA ,JB ,JAE,JE ,JNE} }, /* 8087 R */ 773: #endif 774: }; 775: 776: #define XP (JP << 8) 777: #define XNP (JNP << 8) 778: static const unsigned jfops[1][26] = 779: /* le gt lt ge eqeq ne unord lg leg ule ul uge */ 780: { 781: { XNP|JBE,JA,XNP|JB,JAE,XNP|JE, XP|JNE,JP, JNE,JNP, JBE,JC,XP|JAE, 782: 783: /* ug ue ngt nge nlt nle ord nlg nleg nule nul nuge nug nue */ 784: XP|JA,JE,JBE,JB, XP|JAE,XP|JA, JNP,JE, JP, JA, JNC,XNP|JB, XNP|JBE,JNE }, /* 8087 */ 785: }; 786: 787: assert(e); 788: while (e->Eoper == OPcomma || 789: /* The !EOP(e->E1) is to line up with the case in cdeq() where */ 790: /* we decide if mPSW is passed on when evaluating E2 or not. */ 791: (e->Eoper == OPeq && !EOP(e->E1))) 792: e = e->E2; /* right operand determines it */ 793: 794: op = e->Eoper; 795: if (e->Ecount != e->Ecomsub) // comsubs just get Z bit set 796: return JNE; 797: if (!OTrel(op)) // not relational operator 798: { 799: tym_t tymx = tybasic(e->Ety); 800: if (tyfloating(tymx) && config.inline8087 && 801: (tymx == TYldouble || tymx == TYildouble || tymx == TYcldouble || 802: tymx == TYcdouble || tymx == TYcfloat || 803: op == OPind)) 804: { 805: return XP|JNE; 806: } 807: return (op >= OPbt && op <= OPbts) ? JC : JNE; 808: } 809: 810: if (e->E2->Eoper == OPconst) 811: zero = !boolres(e->E2); 812: else 813: zero = 0; 814: 815: tym = e->E1->Ety; 816: if (tyfloating(tym)) 817: #if 1 818: { i = 0; 819: if (config.inline8087) 820: { i = 1; 821: 822: #if 1 823: #define NOSAHF I64 824: if (rel_exception(op) || config.flags4 & CFG4fastfloat) 825: { 826: if (zero) 827: { 828: if (NOSAHF) 829: op = swaprel(op); 830: } 831: else if (NOSAHF) 832: op = swaprel(op); 833: else if (cmporder87(e->E2)) 834: op = swaprel(op); 835: else 836: ; 837: } 838: else 839: { 840: if (zero && config.target_cpu < TARGET_80386) 841: ; 842: else 843: op = swaprel(op); 844: } 845: #else 846: if (zero && !rel_exception(op) && config.target_cpu >= TARGET_80386) 847: op = swaprel(op); 848: else if (!zero && 849: (cmporder87(e->E2) || !(rel_exception(op) || config.flags4 & CFG4fastfloat))) 850: /* compare is reversed */ 851: op = swaprel(op); 852: #endif 853: } 854: jp = jfops[0][op - OPle]; 855: goto L1; 856: } 857: #else 858: i = (config.inline8087) ? (3 + cmporder87(e->E2)) : 2; 859: #endif 860: else if (tyuns(tym) || tyuns(e->E2->Ety)) 861: i = 1; 862: else if (tyintegral(tym) || typtr(tym)) 863: i = 0; 864: else 865: { 866: #if DEBUG 867: elem_print(e); 868: WRTYxx(tym); 869: #endif 870: assert(0); 871: } 872: 873: jp = jops[i][zero][op - OPle]; /* table starts with OPle */ 874: L1: 875: #if DEBUG 876: if ((jp & 0xF0) != 0x70) 877: WROP(op), 878: printf("i %d zero %d op x%x jp x%x\n",i,zero,op,jp); 879: #endif 880: assert((jp & 0xF0) == 0x70); 881: return jp; 882: } 883: 884: /********************************** 885: * Append code to *pc which validates pointer described by 886: * addressing mode in *pcs. Modify addressing mode in *pcs. 887: * Input: 888: * keepmsk mask of registers we must not destroy or use 889: * if (keepmsk & RMstore), this will be only a store operation 890: * into the lvalue 891: */ 892: 893: void cod3_ptrchk(code **pc,code *pcs,regm_t keepmsk) 894: { code *c; 895: code *cs2; 896: unsigned char rm,sib;
warning C4101: 'sib' : unreferenced local variable
897: unsigned reg; 898: unsigned flagsave; 899: unsigned opsave; 900: regm_t idxregs; 901: regm_t tosave; 902: regm_t used; 903: int i; 904: 905: assert(!I64); 906: if (!I16 && pcs->Iflags & (CFes | CFss | CFcs | CFds | CFfs | CFgs))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
907: return; // not designed to deal with 48 bit far pointers 908: 909: c = *pc; 910: 911: rm = pcs->Irm; 912: assert(!(rm & 0x40)); // no disp8 or reg addressing modes 913: 914: // If the addressing mode is already a register 915: reg = rm & 7; 916: if (I16) 917: { static const unsigned char imode[8] = { BP,BP,BP,BP,SI,DI,BP,BX }; 918: 919: reg = imode[reg]; // convert [SI] to SI, etc. 920: } 921: idxregs = mask[reg]; 922: if ((rm & 0x80 && (pcs->IFL1 != FLoffset || pcs->IEV1.Vuns)) || 923: !(idxregs & ALLREGS) 924: ) 925: { 926: // Load the offset into a register, so we can push the address 927: idxregs = (I16 ? IDXREGS : ALLREGS) & ~keepmsk; // only these can be index regs 928: assert(idxregs); 929: c = cat(c,allocreg(&idxregs,&reg,TYoffset)); 930: 931: opsave = pcs->Iop; 932: flagsave = pcs->Iflags; 933: pcs->Iop = 0x8D; 934: pcs->Irm |= modregrm(0,reg,0); 935: pcs->Iflags &= ~(CFopsize | CFss | CFes | CFcs); // no prefix bytes needed 936: c = gen(c,pcs); // LEA reg,EA 937: 938: pcs->Iflags = flagsave; 939: pcs->Iop = opsave; 940: } 941: 942: // registers destroyed by the function call 943: //used = (mBP | ALLREGS | mES) & ~fregsaved; 944: used = 0; // much less code generated this way 945: 946: cs2 = CNIL; 947: tosave = used & (keepmsk | idxregs); 948: for (i = 0; tosave; i++) 949: { regm_t mi = mask[i]; 950: 951: assert(i < REGMAX); 952: if (mi & tosave) /* i = register to save */ 953: { 954: int push,pop; 955: 956: stackchanged = 1; 957: if (i == ES) 958: { push = 0x06; 959: pop = 0x07; 960: } 961: else 962: { push = 0x50 + i; 963: pop = push | 8; 964: } 965: c = gen1(c,push); // PUSH i 966: cs2 = cat(gen1(CNIL,pop),cs2); // POP i 967: tosave &= ~mi; 968: } 969: } 970: 971: // For 16 bit models, push a far pointer 972: if (I16) 973: { int segreg; 974: 975: switch (pcs->Iflags & (CFes | CFss | CFcs | CFds | CFfs | CFgs)) 976: { case CFes: segreg = 0x06; break; 977: case CFss: segreg = 0x16; break; 978: case CFcs: segreg = 0x0E; break; 979: case 0: segreg = 0x1E; break; // DS 980: default: 981: assert(0); 982: } 983: 984: // See if we should default to SS: 985: // (Happens when BP is part of the addressing mode) 986: if (segreg == 0x1E && (rm & 0xC0) != 0xC0 && 987: rm & 2 && (rm & 7) != 7) 988: { segreg = 0x16; 989: if (config.wflags & WFssneds) 990: pcs->Iflags |= CFss; // because BP won't be there anymore 991: } 992: c = gen1(c,segreg); // PUSH segreg 993: } 994: 995: c = gen1(c,0x50 + reg); // PUSH reg 996: 997: // Rewrite the addressing mode in *pcs so it is just 0[reg] 998: setaddrmode(pcs, idxregs); 999: pcs->IFL1 = FLoffset; 1000: pcs->IEV1.Vuns = 0; 1001: 1002: // Call the validation function 1003: { 1004: makeitextern(rtlsym[RTLSYM_PTRCHK]); 1005: 1006: used &= ~(keepmsk | idxregs); // regs destroyed by this exercise 1007: c = cat(c,getregs(used)); 1008: // CALL __ptrchk 1009: gencs(c,(LARGECODE) ? 0x9A : CALL,0,FLfunc,rtlsym[RTLSYM_PTRCHK]); 1010: } 1011: 1012: *pc = cat(c,cs2); 1013: } 1014: 1015: 1016: 1017: /*********************************** 1018: * Determine if BP can be used as a general purpose register. 1019: * Note parallels between this routine and prolog(). 1020: * Returns: 1021: * 0 can't be used, needed for frame 1022: * mBP can be used 1023: */ 1024: 1025: regm_t cod3_useBP() 1026: { 1027: tym_t tym; 1028: tym_t tyf; 1029: 1030: // Note that DOSX memory model cannot use EBP as a general purpose 1031: // register, as SS != DS. 1032: if (!(config.exe & EX_flat) || config.flags & (CFGalwaysframe | CFGnoebp)) 1033: goto Lcant; 1034: 1035: if (anyiasm) 1036: goto Lcant; 1037: 1038: tyf = funcsym_p->ty(); 1039: if (tyf & mTYnaked) // if no prolog/epilog for function 1040: goto Lcant; 1041: 1042: if (funcsym_p->Sfunc->Fflags3 & Ffakeeh) 1043: { 1044: goto Lcant; // need consistent stack frame 1045: } 1046: 1047: tym = tybasic(tyf); 1048: if (tym == TYifunc) 1049: goto Lcant; 1050: 1051: stackoffsets(0); 1052: localsize = Aoffset; // an estimate only 1053: // if (localsize) 1054: { 1055: if (!(config.flags4 & CFG4speed) || 1056: config.target_cpu < TARGET_Pentium || 1057: tyfarfunc(tym) || 1058: config.flags & CFGstack || 1059: localsize >= 0x100 || // arbitrary value < 0x1000 1060: (usednteh & ~NTEHjmonitor) || 1061: usedalloca 1062: ) 1063: goto Lcant; 1064: } 1065: Lcan:
warning C4102: 'Lcan' : unreferenced label
1066: return mBP; 1067: 1068: Lcant: 1069: return 0; 1070: } 1071: 1072: /*************************************** 1073: * Gen code for OPframeptr 1074: */ 1075: 1076: code *cdframeptr(elem *e, regm_t *pretregs) 1077: { 1078: unsigned reg; 1079: code cs; 1080: 1081: regm_t retregs = *pretregs & allregs; 1082: if (!retregs) 1083: retregs = allregs; 1084: code *cg = allocreg(&retregs, &reg, TYint); 1085: 1086: cs.Iop = ESCAPE | ESCframeptr; 1087: cs.Iflags = 0; 1088: cs.Irex = 0; 1089: cs.Irm = reg; 1090: cg = gen(cg,&cs); 1091: 1092: return cat(cg,fixresult(e,retregs,pretregs)); 1093: } 1094: 1095: /*************************************** 1096: * Gen code for load of _GLOBAL_OFFSET_TABLE_. 1097: * This value gets cached in the local variable 'localgot'. 1098: */ 1099: 1100: code *cdgot(elem *e, regm_t *pretregs) 1101: { 1102: #if TARGET_OSX 1103: regm_t retregs; 1104: unsigned reg; 1105: code *c; 1106: 1107: retregs = *pretregs & allregs; 1108: if (!retregs) 1109: retregs = allregs; 1110: c = allocreg(&retregs, &reg, TYnptr); 1111: 1112: c = genc(c,CALL,0,0,0,FLgot,0); // CALL L1 1113: gen1(c, 0x58 + reg); // L1: POP reg 1114: 1115: return cat(c,fixresult(e,retregs,pretregs)); 1116: #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1117: regm_t retregs; 1118: unsigned reg; 1119: code *c; 1120: code *cgot; 1121: 1122: retregs = *pretregs & allregs; 1123: if (!retregs) 1124: retregs = allregs; 1125: c = allocreg(&retregs, &reg, TYnptr); 1126: 1127: c = genc2(c,CALL,0,0); // CALL L1 1128: gen1(c, 0x58 + reg); // L1: POP reg 1129: 1130: // ADD reg,_GLOBAL_OFFSET_TABLE_+3 1131: symbol *gotsym = elfobj_getGOTsym(); 1132: cgot = gencs(CNIL,0x81,modregrm(3,0,reg),FLextern,gotsym); 1133: /* Because the 2:3 offset from L1: is hardcoded, 1134: * this sequence of instructions must not 1135: * have any instructions in between, 1136: * so set CFvolatile to prevent the scheduler from rearranging it. 1137: */ 1138: cgot->Iflags = CFoff | CFvolatile; 1139: cgot->IEVoffset2 = (reg == AX) ? 2 : 3; 1140: 1141: makeitextern(gotsym); 1142: return cat3(c,cgot,fixresult(e,retregs,pretregs)); 1143: #else 1144: assert(0); 1145: return NULL; 1146: #endif 1147: } 1148: 1149: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1150: /***************************** 1151: * Returns: 1152: * # of bytes stored 1153: */ 1154: 1155: #define ONS_OHD 4 // max # of extra bytes added by obj_namestring() 1156: 1157: STATIC int obj_namestring(char *p,const char *name) 1158: { unsigned len; 1159: 1160: len = strlen(name); 1161: if (len > 255) 1162: { 1163: short *ps = (short *)p; 1164: p[0] = 0xFF; 1165: p[1] = 0; 1166: ps[1] = len; 1167: memcpy(p + 4,name,len); 1168: len += ONS_OHD; 1169: } 1170: else 1171: { p[0] = len; 1172: memcpy(p + 1,name,len); 1173: len++; 1174: } 1175: return len; 1176: } 1177: #endif 1178: 1179: /******************************* 1180: * Generate code for a function start. 1181: * Input: 1182: * Coffset address of start of code 1183: * Output: 1184: * Coffset adjusted for size of code generated 1185: * EBPtoESP 1186: * hasframe 1187: * BPoff 1188: */ 1189: 1190: code *prolog() 1191: { 1192: SYMIDX si; 1193: unsigned reg; 1194: char enter; 1195: unsigned Foffset; 1196: unsigned xlocalsize; // amount to subtract from ESP to make room for locals 1197: unsigned pushallocreg; 1198: char guessneedframe; 1199: regm_t namedargs = 0; 1200: 1201: //printf("cod3.prolog(), needframe = %d, Aalign = %d\n", needframe, Aalign); 1202: debugx(debugw && printf("funcstart()\n")); 1203: regcon.immed.mval = 0; /* no values in registers yet */ 1204: EBPtoESP = -REGSIZE; 1205: hasframe = 0; 1206: char pushds = 0; 1207: BPoff = 0; 1208: code *c = CNIL; 1209: int pushalloc = 0; 1210: tym_t tyf = funcsym_p->ty(); 1211: tym_t tym = tybasic(tyf); 1212: unsigned farfunc = tyfarfunc(tym); 1213: pushallocreg = (tyf == TYmfunc) ? CX : AX; 1214: if (config.flags & CFGalwaysframe || funcsym_p->Sfunc->Fflags3 & Ffakeeh) 1215: needframe = 1; 1216: 1217: Lagain: 1218: guessneedframe = needframe; 1219: // if (needframe && config.exe & (EX_LINUX | EX_FREEBSD | EX_SOLARIS) && !(usednteh & ~NTEHjmonitor)) 1220: // usednteh |= NTEHpassthru; 1221: 1222: /* Compute BP offsets for variables on stack. 1223: * The organization is: 1224: * Poff parameters 1225: * seg of return addr (if far function) 1226: * IP of return addr 1227: * BP-> caller's BP 1228: * DS (if Windows prolog/epilog) 1229: * exception handling context symbol 1230: * Aoff autos and regs 1231: * regsave.off any saved registers 1232: * Foff floating register 1233: * AAoff alloca temporary 1234: * CSoff common subs 1235: * NDPoff any 8087 saved registers 1236: * Toff temporaries 1237: * monitor context record 1238: * any saved registers 1239: */ 1240: 1241: if (tym == TYifunc) 1242: Poff = 26; 1243: else if (I64) 1244: Poff = 16; 1245: else if (I32) 1246: Poff = farfunc ? 12 : 8; 1247: else 1248: Poff = farfunc ? 6 : 4; 1249: 1250: Aoff = 0; 1251: #if NTEXCEPTIONS == 2 1252: Aoff -= nteh_contextsym_size(); 1253: #if MARS 1254: if (funcsym_p->Sfunc->Fflags3 & Ffakeeh && nteh_contextsym_size() == 0) 1255: Aoff -= 5 * 4; 1256: #endif 1257: #endif 1258: Aoff = -align(0,-Aoff + Aoffset);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
warning C4146: unary minus operator applied to unsigned type, result still unsigned
1259: 1260: if (Aalign > REGSIZE) 1261: { 1262: // Adjust Aoff so that it is Aalign byte aligned, assuming that 1263: // before function parameters were pushed the stack was 1264: // Aalign byte aligned 1265: int sz = Poffset + -Aoff + Poff + (needframe ? 0 : REGSIZE);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
1266: if (sz & (Aalign - 1)) 1267: Aoff -= sz - (sz & (Aalign - 1)); 1268: } 1269: 1270: regsave.off = Aoff - align(0,regsave.top); 1271: Foffset = floatreg ? DOUBLESIZE : 0; 1272: Foff = regsave.off - align(0,Foffset); 1273: assert(usedalloca != 1); 1274: AAoff = usedalloca ? (Foff - REGSIZE) : Foff; 1275: CSoff = AAoff - align(0,cstop * REGSIZE); 1276: NDPoff = CSoff - align(0,NDP::savetop * NDPSAVESIZE); 1277: Toff = NDPoff - align(0,Toffset); 1278: localsize = -Toff;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
1279: 1280: regm_t topush = fregsaved & ~mfuncreg; // mask of registers that need saving 1281: int npush = 0; // number of registers that need saving 1282: for (regm_t x = topush; x; x >>= 1) 1283: npush += x & 1; 1284: 1285: // Keep the stack aligned by 8 for any subsequent function calls 1286: if (!I16 && calledafunc &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1287: (STACKALIGN == 16 || config.flags4 & CFG4stackalign)) 1288: { 1289: //printf("npush = %d Poff = x%x needframe = %d localsize = x%x\n", npush, Poff, needframe, localsize); 1290: 1291: int sz = Poff + (needframe ? 0 : -REGSIZE) + localsize + npush * REGSIZE; 1292: if (STACKALIGN == 16) 1293: { 1294: if (sz & (8|4)) 1295: localsize += STACKALIGN - (sz & (8|4)); 1296: } 1297: else if (sz & 4) 1298: localsize += 4; 1299: } 1300: 1301: //printf("Foff x%02x Aoff x%02x Toff x%02x NDPoff x%02x CSoff x%02x Poff x%02x localsize x%02x\n", 1302: //(int)Foff,(int)Aoff,(int)Toff,(int)NDPoff,(int)CSoff,(int)Poff,(int)localsize); 1303: 1304: xlocalsize = localsize; 1305: 1306: if (tyf & mTYnaked) // if no prolog/epilog for function 1307: { 1308: hasframe = 1; 1309: return NULL; 1310: } 1311: 1312: if (tym == TYifunc) 1313: { static unsigned char ops2[] = { 0x60,0x1E,0x06,0 }; 1314: static unsigned char ops0[] = { 0x50,0x51,0x52,0x53, 1315: 0x54,0x55,0x56,0x57, 1316: 0x1E,0x06,0 }; 1317: 1318: unsigned char *p; 1319: 1320: p = (config.target_cpu >= TARGET_80286) ? ops2 : ops0; 1321: do 1322: c = gen1(c,*p); 1323: while (*++p); 1324: c = genregs(c,0x8B,BP,SP); // MOV BP,SP 1325: if (localsize) 1326: c = genc2(c,0x81,modregrm(3,5,SP),localsize); // SUB SP,localsize 1327: tyf |= mTYloadds; 1328: hasframe = 1; 1329: goto Lcont; 1330: } 1331: 1332: /* Determine if we need BP set up */ 1333: if (config.flags & CFGalwaysframe) 1334: needframe = 1; 1335: else 1336: { 1337: if (localsize) 1338: { 1339: if (I16 || 1340: !(config.flags4 & CFG4speed) || 1341: config.target_cpu < TARGET_Pentium || 1342: farfunc || 1343: config.flags & CFGstack || 1344: xlocalsize >= 0x1000 || 1345: (usednteh & ~NTEHjmonitor) || 1346: anyiasm || 1347: usedalloca 1348: ) 1349: needframe = 1; 1350: } 1351: if (refparam && (anyiasm || I16)) 1352: needframe = 1; 1353: } 1354: 1355: if (needframe) 1356: { assert(mfuncreg & mBP); // shouldn't have used mBP 1357: 1358: if (!guessneedframe) // if guessed wrong 1359: goto Lagain; 1360: } 1361: 1362: if (I16 && config.wflags & WFwindows && farfunc) 1363: { int wflags; 1364: int segreg; 1365: 1366: #if SCPP 1367: // alloca() can't be because the 'special' parameter won't be at 1368: // a known offset from BP. 1369: if (usedalloca == 1) 1370: synerr(EM_alloca_win); // alloca() can't be in Windows functions 1371: #endif 1372: 1373: wflags = config.wflags; 1374: if (wflags & WFreduced && !(tyf & mTYexport)) 1375: { // reduced prolog/epilog for non-exported functions 1376: wflags &= ~(WFdgroup | WFds | WFss); 1377: } 1378: 1379: c = getregs(mAX); 1380: assert(!c); /* should not have any value in AX */ 1381: 1382: switch (wflags & (WFdgroup | WFds | WFss)) 1383: { case WFdgroup: // MOV AX,DGROUP 1384: if (wflags & WFreduced) 1385: tyf &= ~mTYloadds; // remove redundancy 1386: c = genc(c,0xC7,modregrm(3,0,AX),0,0,FLdatseg,(targ_uns) 0); 1387: c->Iflags ^= CFseg | CFoff; // turn off CFoff, on CFseg 1388: break; 1389: case WFss: 1390: segreg = 2; // SS 1391: goto Lmovax; 1392: case WFds: 1393: segreg = 3; // DS 1394: Lmovax: 1395: c = gen2(c,0x8C,modregrm(3,segreg,AX)); // MOV AX,segreg 1396: if (wflags & WFds) 1397: gen1(c,0x90); // NOP 1398: break; 1399: case 0: 1400: break; 1401: default: 1402: #ifdef DEBUG 1403: printf("config.wflags = x%x\n",config.wflags); 1404: #endif 1405: assert(0); 1406: } 1407: if (wflags & WFincbp) 1408: c = gen1(c,0x40 + BP); // INC BP 1409: c = gen1(c,0x50 + BP); // PUSH BP 1410: genregs(c,0x8B,BP,SP); // MOV BP,SP 1411: if (wflags & (WFsaveds | WFds | WFss | WFdgroup)) 1412: { gen1(c,0x1E); // PUSH DS 1413: pushds = TRUE; 1414: BPoff = -REGSIZE; 1415: } 1416: if (wflags & (WFds | WFss | WFdgroup)) 1417: gen2(c,0x8E,modregrm(3,3,AX)); // MOV DS,AX 1418: 1419: enter = FALSE; /* don't use ENTER instruction */ 1420: hasframe = 1; /* we have a stack frame */ 1421: } 1422: else 1423: if (needframe) // if variables or parameters 1424: { 1425: if (config.wflags & WFincbp && farfunc) 1426: c = gen1(c,0x40 + BP); /* INC BP */ 1427: if (config.target_cpu < TARGET_80286 || 1428: config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64) || 1429: !localsize || 1430: config.flags & CFGstack || 1431: (xlocalsize >= 0x1000 && config.exe & EX_flat) || 1432: localsize >= 0x10000 || 1433: #if NTEXCEPTIONS == 2 1434: (usednteh & ~NTEHjmonitor && (config.flags2 & CFG2seh)) || 1435: #endif 1436: (config.target_cpu >= TARGET_80386 && 1437: config.flags4 & CFG4speed) 1438: ) 1439: { 1440: c = gen1(c,0x50 + BP); // PUSH BP 1441: genregs(c,0x8B,BP,SP); // MOV BP,SP 1442: if (I64) 1443: code_orrex(c, REX_W); // MOV RBP,RSP 1444: #if ELFOBJ || MACHOBJ 1445: if (config.fulltypes) 1446: // Don't reorder instructions, as dwarf CFA relies on it 1447: code_orflag(c, CFvolatile); 1448: #endif 1449: enter = FALSE; /* do not use ENTER instruction */ 1450: #if NTEXCEPTIONS == 2 1451: if (usednteh & ~NTEHjmonitor && (config.flags2 & CFG2seh)) 1452: { 1453: code *ce = nteh_prolog(); 1454: c = cat(c,ce); 1455: int sz = nteh_contextsym_size(); 1456: assert(sz != 0); // should be 5*4, not 0 1457: xlocalsize -= sz; // sz is already subtracted from ESP 1458: // by nteh_prolog() 1459: } 1460: #endif 1461: #if ELFOBJ || MACHOBJ 1462: if (config.fulltypes) 1463: { int off = I64 ? 16 : 8; 1464: dwarf_CFA_set_loc(1); // address after PUSH EBP 1465: dwarf_CFA_set_reg_offset(SP, off); // CFA is now 8[ESP] 1466: dwarf_CFA_offset(BP, -off); // EBP is at 0[ESP] 1467: dwarf_CFA_set_loc(3); // address after MOV EBP,ESP 1468: // Yes, I know the parameter is 8 when we mean 0! 1469: // But this gets the cfa register set to EBP correctly 1470: dwarf_CFA_set_reg_offset(BP, off); // CFA is now 0[EBP] 1471: } 1472: #endif 1473: } 1474: else 1475: enter = TRUE; 1476: hasframe = 1; 1477: } 1478: 1479: if (config.flags & CFGstack) /* if stack overflow check */ 1480: goto Ladjstack; 1481: 1482: if (needframe) /* if variables or parameters */ 1483: { 1484: if (xlocalsize) /* if any stack offset */ 1485: { 1486: Ladjstack: 1487: #if !TARGET_LINUX // seems that Linux doesn't need to fault in stack pages 1488: if ((config.flags & CFGstack && !(I32 && xlocalsize < 0x1000)) // if stack overflow check 1489: #if TARGET_WINDOS 1490: || (xlocalsize >= 0x1000 && config.exe & EX_flat) 1491: #endif 1492: ) 1493: { 1494: if (I16) 1495: { 1496: // BUG: Won't work if parameter is passed in AX 1497: c = movregconst(c,AX,xlocalsize,FALSE); // MOV AX,localsize 1498: makeitextern(rtlsym[RTLSYM_CHKSTK]); 1499: // CALL _chkstk 1500: gencs(c,(LARGECODE) ? 0x9A : CALL,0,FLfunc,rtlsym[RTLSYM_CHKSTK]); 1501: useregs((ALLREGS | mBP | mES) & ~rtlsym[RTLSYM_CHKSTK]->Sregsaved); 1502: } 1503: else 1504: { 1505: /* Watch out for 64 bit code where EDX is passed as a register parameter 1506: */ 1507: int reg = I64 ? R11 : DX; // scratch register
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1193' of 'c:\projects\extern\d\dmd\src\backend\cod3.c': Lines: 1193
1508: 1509: /* MOV EDX, xlocalsize/0x1000 1510: * L1: SUB ESP, 0x1000 1511: * TEST [ESP],ESP 1512: * DEC EDX 1513: * JNE L1 1514: * SUB ESP, xlocalsize % 0x1000 1515: */ 1516: c = movregconst(c, reg, xlocalsize / 0x1000, FALSE); 1517: code *csub = genc2(NULL,0x81,modregrm(3,5,SP),0x1000); 1518: if (I64) 1519: code_orrex(csub, REX_W); 1520: code_orflag(csub, CFtarg2); 1521: gen2sib(csub, 0x85, modregrm(0,SP,4),modregrm(0,4,SP)); 1522: if (I64) 1523: { gen2(csub, 0xFF, (REX_W << 16) | modregrmx(3,0,R11)); // DEC R11 1524: genc2(csub,JNE,0,(targ_uns)-14); 1525: } 1526: else 1527: { gen1(csub, 0x48 + DX); // DEC EDX 1528: genc2(csub,JNE,0,(targ_uns)-12); 1529: } 1530: regimmed_set(reg,0); // reg is now 0 1531: genc2(csub,0x81,modregrm(3,5,SP),xlocalsize & 0xFFF); 1532: if (I64) 1533: code_orrex(csub, REX_W); 1534: c = cat(c,csub); 1535: useregs(mask[reg]); 1536: } 1537: } 1538: else 1539: #endif 1540: { 1541: if (enter) 1542: { // ENTER xlocalsize,0 1543: c = genc(c,0xC8,0,FLconst,xlocalsize,FLconst,(targ_uns) 0); 1544: #if ELFOBJ || MACHOBJ 1545: assert(!config.fulltypes); // didn't emit Dwarf data 1546: #endif 1547: } 1548: else if (xlocalsize == REGSIZE && config.flags4 & CFG4optimized) 1549: { c = gen1(c,0x50 + pushallocreg); // PUSH AX 1550: // Do this to prevent an -x[EBP] to be moved in 1551: // front of the push. 1552: code_orflag(c,CFvolatile); 1553: pushalloc = 1; 1554: } 1555: else 1556: { // SUB SP,xlocalsize 1557: c = genc2(c,0x81,modregrm(3,5,SP),xlocalsize); 1558: if (I64) 1559: code_orrex(c, REX_W); 1560: } 1561: } 1562: 1563: if (usedalloca) 1564: { 1565: // Set up magic parameter for alloca() 1566: // MOV -REGSIZE[BP],localsize - BPoff 1567: //c = genc(c,0xC7,modregrm(2,0,BPRM),FLconst,-REGSIZE,FLconst,localsize - BPoff); 1568: c = genc(c,0xC7,modregrm(2,0,BPRM), 1569: FLconst,AAoff + BPoff, 1570: FLconst,localsize - BPoff); 1571: if (I64) 1572: code_orrex(c, REX_W); 1573: } 1574: } 1575: else 1576: assert(usedalloca == 0); 1577: } 1578: else if (xlocalsize) 1579: { 1580: assert(I32); 1581: 1582: if (xlocalsize == REGSIZE) 1583: { c = gen1(c,0x50 + pushallocreg); // PUSH AX 1584: pushalloc = 1; 1585: } 1586: else if (xlocalsize == 2 * REGSIZE) 1587: { c = gen1(c,0x50 + pushallocreg); // PUSH AX 1588: gen1(c,0x50 + pushallocreg); // PUSH AX 1589: pushalloc = 1; 1590: } 1591: else 1592: { // SUB ESP,xlocalsize 1593: c = genc2(c,0x81,modregrm(3,5,SP),xlocalsize); 1594: if (I64) 1595: code_orrex(c, REX_W); 1596: } 1597: BPoff += REGSIZE; 1598: } 1599: else 1600: assert((localsize | usedalloca) == 0 || (usednteh & NTEHjmonitor)); 1601: EBPtoESP += xlocalsize; 1602: 1603: /* The idea is to generate trace for all functions if -Nc is not thrown. 1604: * If -Nc is thrown, generate trace only for global COMDATs, because those 1605: * are relevant to the FUNCTIONS statement in the linker .DEF file. 1606: * This same logic should be in epilog(). 1607: */ 1608: if (config.flags & CFGtrace && 1609: (!(config.flags4 & CFG4allcomdat) || 1610: funcsym_p->Sclass == SCcomdat || 1611: funcsym_p->Sclass == SCglobal || 1612: (config.flags2 & CFG2comdat && SymInline(funcsym_p)) 1613: ) 1614: ) 1615: { 1616: if (STACKALIGN == 16 && npush) 1617: { /* This could be avoided by moving the function call to after the 1618: * registers are saved. But I don't remember why the call is here 1619: * and not there. 1620: */ 1621: c = genc2(c,0x81,modregrm(3,5,SP),npush * REGSIZE); // SUB ESP,npush * REGSIZE 1622: if (I64) 1623: code_orrex(c, REX_W); 1624: } 1625: 1626: symbol *s = rtlsym[farfunc ? RTLSYM_TRACE_PRO_F : RTLSYM_TRACE_PRO_N]; 1627: makeitextern(s); 1628: c = gencs(c,I16 ? 0x9A : CALL,0,FLfunc,s); // CALL _trace 1629: if (!I16) 1630: code_orflag(c,CFoff | CFselfrel); 1631: /* Embedding the function name inline after the call works, but it 1632: * makes disassembling the code annoying. 1633: */ 1634: #if ELFOBJ || MACHOBJ 1635: size_t len = strlen(funcsym_p->Sident); 1636: char *buffer = (char *)malloc(len + 4); 1637: assert(buffer); 1638: if (len <= 254) 1639: { buffer[0] = len; 1640: memcpy(buffer + 1, funcsym_p->Sident, len); 1641: len++; 1642: } 1643: else 1644: { buffer[0] = 0xFF; 1645: buffer[1] = 0; 1646: buffer[2] = len & 0xFF; 1647: buffer[3] = len >> 8; 1648: memcpy(buffer + 4, funcsym_p->Sident, len); 1649: len += 4; 1650: } 1651: genasm(c, buffer, len); // append func name 1652: free(buffer); 1653: #else 1654: char name[IDMAX+IDOHD+1]; 1655: size_t len = obj_mangle(funcsym_p,name); 1656: assert(len < sizeof(name)); 1657: genasm(c,name,len); // append func name 1658: #endif 1659: if (STACKALIGN == 16 && npush) 1660: { 1661: c = genc2(c,0x81,modregrm(3,0,SP),npush * REGSIZE); // ADD ESP,npush * REGSIZE 1662: if (I64) 1663: code_orrex(c, REX_W); 1664: } 1665: useregs((ALLREGS | mBP | mES) & ~s->Sregsaved); 1666: } 1667: 1668: #if MARS 1669: if (usednteh & NTEHjmonitor) 1670: { Symbol *sthis; 1671: 1672: for (si = 0; 1; si++) 1673: { assert(si < globsym.top); 1674: sthis = globsym.tab[si]; 1675: if (strcmp(sthis->Sident,"this") == 0) 1676: break; 1677: } 1678: c = cat(c,nteh_monitor_prolog(sthis)); 1679: EBPtoESP += 3 * 4; 1680: } 1681: #endif 1682: 1683: while (topush) /* while registers to push */ 1684: { reg = findreg(topush); 1685: topush &= ~mask[reg]; 1686: c = gen1(c,0x50 + (reg & 7)); 1687: if (reg & 8) 1688: code_orrex(c, REX_B); 1689: EBPtoESP += REGSIZE; 1690: #if ELFOBJ || MACHOBJ 1691: if (config.fulltypes) 1692: { // Emit debug_frame data giving location of saved register 1693: // relative to 0[EBP] 1694: pinholeopt(c, NULL); 1695: dwarf_CFA_set_loc(calcblksize(c)); // address after PUSH reg 1696: dwarf_CFA_offset(reg, -EBPtoESP - REGSIZE); 1697: } 1698: #endif 1699: } 1700: 1701: Lcont: 1702: 1703: /* Determine if we need to reload DS */ 1704: if (tyf & mTYloadds) 1705: { code *c1; 1706: 1707: if (!pushds) // if not already pushed 1708: c = gen1(c,0x1E); // PUSH DS 1709: c1 = genc(CNIL,0xC7,modregrm(3,0,AX),0,0,FLdatseg,(targ_uns) 0); /* MOV AX,DGROUP */ 1710: c1->Iflags ^= CFseg | CFoff; /* turn off CFoff, on CFseg */ 1711: c = cat(c,c1); 1712: gen2(c,0x8E,modregrm(3,3,AX)); /* MOV DS,AX */ 1713: useregs(mAX); 1714: } 1715: 1716: if (tym == TYifunc) 1717: c = gen1(c,0xFC); // CLD 1718: 1719: #if NTEXCEPTIONS == 2 1720: if (usednteh & NTEH_except) 1721: c = cat(c,nteh_setsp(0x89)); // MOV __context[EBP].esp,ESP 1722: #endif 1723: 1724: // Load register parameters off of the stack. Do not use 1725: // assignaddr(), as it will replace the stack reference with 1726: // the register! 1727: for (si = 0; si < globsym.top; si++) 1728: { symbol *s = globsym.tab[si]; 1729: code *c2; 1730: unsigned sz = type_size(s->Stype); 1731: 1732: if ((s->Sclass == SCregpar || s->Sclass == SCparameter) && 1733: s->Sfl == FLreg && 1734: (refparam 1735: #if MARS 1736: // This variable has been reference by a nested function 1737: || s->Stype->Tty & mTYvolatile 1738: #endif 1739: )) 1740: { 1741: /* MOV reg,param[BP] */ 1742: //assert(refparam); 1743: code *c2 = genc1(CNIL,0x8B ^ (sz == 1),
warning C4806: '^' : unsafe operation: no value of type 'bool' promoted to type 'int' can equal the given constant
warning C6246: Local declaration of 'c2' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1729' of 'c:\projects\extern\d\dmd\src\backend\cod3.c': Lines: 1729
1744: modregxrm(2,s->Sreglsw,BPRM),FLconst,Poff + s->Soffset); 1745: if (!I16 && sz == SHORTSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1746: c2->Iflags |= CFopsize; // operand size 1747: if (I64 && sz == REGSIZE) 1748: c2->Irex |= REX_W; 1749: if (!hasframe) 1750: { /* Convert to ESP relative address rather than EBP */ 1751: assert(!I16); 1752: c2->Irm = modregxrm(2,s->Sreglsw,4); 1753: c2->Isib = modregrm(0,4,SP); 1754: c2->IEVpointer1 += EBPtoESP; 1755: } 1756: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
1757: { 1758: code *c3 = genc1(CNIL,0x8B, 1759: modregxrm(2,s->Sregmsw,BPRM),FLconst,Poff + s->Soffset + REGSIZE); 1760: if (I64) 1761: c3->Irex |= REX_W; 1762: if (!hasframe) 1763: { /* Convert to ESP relative address rather than EBP */ 1764: assert(!I16); 1765: c3->Irm = modregxrm(2,s->Sregmsw,4); 1766: c3->Isib = modregrm(0,4,SP); 1767: c3->IEVpointer1 += EBPtoESP; 1768: } 1769: c2 = cat(c2,c3); 1770: } 1771: c = cat(c,c2); 1772: } 1773: else if (s->Sclass == SCfastpar) 1774: { // Argument is passed in a register 1775: unsigned preg = s->Spreg; 1776: 1777: namedargs |= mask[preg]; 1778: 1779: if (s->Sfl == FLreg) 1780: { // MOV reg,preg 1781: c = genmovreg(c,s->Sreglsw,preg); 1782: if (I64 && sz == 8) 1783: code_orrex(c, REX_W); 1784: } 1785: else if (s->Sflags & SFLdead || 1786: (!anyiasm && !(s->Sflags & SFLread) && s->Sflags & SFLunambig && 1787: #if MARS 1788: // This variable has been reference by a nested function 1789: !(s->Stype->Tty & mTYvolatile) && 1790: #endif 1791: (config.flags4 & CFG4optimized || !config.fulltypes))) 1792: { 1793: // Ignore it, as it is never referenced 1794: ; 1795: } 1796: else 1797: { 1798: targ_size_t offset = Aoff + BPoff + s->Soffset; 1799: int op = 0x89; // MOV x[EBP],preg 1800: if (preg >= XMM0 && preg <= XMM15) 1801: { 1802: if (sz == 8) 1803: op = 0xF20F11; // MOVSD x[EBP],preg 1804: else 1805: { 1806: assert(sz == 4); 1807: op = 0xF30F11; // MOVSS x[EBP],preg 1808: } 1809: } 1810: if (hasframe) 1811: { 1812: if (!(pushalloc && preg == pushallocreg)) 1813: { 1814: // MOV x[EBP],preg 1815: c2 = genc1(CNIL,op, 1816: modregxrm(2,preg,BPRM),FLconst, offset); 1817: if (preg >= XMM0 && preg <= XMM15) 1818: { 1819: } 1820: else 1821: { 1822: //printf("%s Aoff = %d, BPoff = %d, Soffset = %d, sz = %d\n", s->Sident, (int)Aoff, (int)BPoff, (int)s->Soffset, (int)sz); 1823: // if (offset & 2) 1824: // c2->Iflags |= CFopsize; 1825: if (I64 && sz == 8) 1826: code_orrex(c2, REX_W); 1827: } 1828: c = cat(c, c2); 1829: } 1830: } 1831: else 1832: { 1833: offset += EBPtoESP; 1834: if (!(pushalloc && preg == pushallocreg)) 1835: { 1836: // MOV offset[ESP],preg 1837: // BUG: byte size? 1838: c2 = genc1(CNIL,op, 1839: (modregrm(0,4,SP) << 8) | 1840: modregxrm(2,preg,4),FLconst,offset); 1841: if (preg >= XMM0 && preg <= XMM15) 1842: { 1843: } 1844: else 1845: { 1846: if (I64 && sz == 8) 1847: c2->Irex |= REX_W; 1848: // if (offset & 2) 1849: // c2->Iflags |= CFopsize; 1850: } 1851: c = cat(c,c2); 1852: } 1853: } 1854: } 1855: } 1856: } 1857: 1858: /* Load arguments passed in registers into the varargs save area 1859: * so they can be accessed by va_arg(). 1860: */ 1861: if (I64 && variadic(funcsym_p->Stype)) 1862: { 1863: /* Look for __va_argsave 1864: */ 1865: symbol *sv = NULL; 1866: for (SYMIDX si = 0; si < globsym.top; si++)
warning C6246: Local declaration of 'si' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1192' of 'c:\projects\extern\d\dmd\src\backend\cod3.c': Lines: 1192
1867: { symbol *s = globsym.tab[si]; 1868: if (s->Sident[0] == '_' && strcmp(s->Sident, "__va_argsave") == 0) 1869: { sv = s; 1870: break; 1871: } 1872: } 1873: 1874: if (sv && !(sv->Sflags & SFLdead)) 1875: { 1876: /* Generate code to move any arguments passed in registers into 1877: * the stack variable __va_argsave, 1878: * so we can reference it via pointers through va_arg(). 1879: * struct __va_argsave_t { 1880: * size_t[6] regs; 1881: * real[8] fpregs; 1882: * uint offset_regs; 1883: * uint offset_fpregs; 1884: * void* stack_args; 1885: * void* reg_args; 1886: * } 1887: * The MOVAPS instructions seg fault if data is not aligned on 1888: * 16 bytes, so this gives us a nice check to ensure no mistakes. 1889: MOV voff+0*8[RBP],EDI 1890: MOV voff+1*8[RBP],ESI 1891: MOV voff+2*8[RBP],RDX 1892: MOV voff+3*8[RBP],RCX 1893: MOV voff+4*8[RBP],R8 1894: MOV voff+5*8[RBP],R9 1895: MOVZX EAX,AL // AL = 0..8, # of XMM registers used 1896: SHL EAX,2 // 4 bytes for each MOVAPS 1897: LEA RDX,offset L2[RIP] 1898: SUB RDX,RAX 1899: LEA RAX,voff+6*8+0x7F[RBP] 1900: JMP EDX 1901: MOVAPS -0x0F[RAX],XMM7 // only save XMM registers if actually used 1902: MOVAPS -0x1F[RAX],XMM6 1903: MOVAPS -0x2F[RAX],XMM5 1904: MOVAPS -0x3F[RAX],XMM4 1905: MOVAPS -0x4F[RAX],XMM3 1906: MOVAPS -0x5F[RAX],XMM2 1907: MOVAPS -0x6F[RAX],XMM1 1908: MOVAPS -0x7F[RAX],XMM0 1909: L2: 1910: MOV 1[RAX],offset_regs // set __va_argsave.offset_regs 1911: MOV 5[RAX],offset_fpregs // set __va_argsave.offset_fpregs 1912: LEA RDX, Poff+Poffset[RBP] 1913: MOV 9[RAX],RDX // set __va_argsave.stack_args 1914: SUB RAX,6*8+0x7F // point to start of __va_argsave 1915: MOV 6*8+8*16+4+4+8[RAX],RAX // set __va_argsave.reg_args 1916: */ 1917: targ_size_t voff = Aoff + BPoff + sv->Soffset; // EBP offset of start of sv 1918: const int vregnum = 6; 1919: const unsigned vsize = vregnum * 8 + 8 * 16; 1920: code *cv = CNIL; 1921: 1922: static unsigned char regs[vregnum] = { DI,SI,DX,CX,R8,R9 }; 1923: 1924: if (!hasframe) 1925: voff += EBPtoESP; 1926: for (int i = 0; i < vregnum; i++) 1927: { 1928: unsigned r = regs[i]; 1929: if (!(mask[r] & namedargs)) // named args are already dealt with 1930: { unsigned ea = (REX_W << 16) | modregxrm(2,r,BPRM); 1931: if (!hasframe) 1932: ea = (REX_W << 16) | (modregrm(0,4,SP) << 8) | modregxrm(2,r,4); 1933: cv = genc1(cv,0x89,ea,FLconst,voff + i*8); 1934: } 1935: } 1936: 1937: cv = genregs(cv,0x0FB6,AX,AX); // MOVZX EAX,AL 1938: genc2(cv,0xC1,modregrm(3,4,AX),2); // SHL EAX,2 1939: int raxoff = voff+6*8+0x7F; 1940: unsigned L2offset = (raxoff < -0x7F) ? 0x2C : 0x29; 1941: if (!hasframe) 1942: L2offset += 1; // +1 for sib byte 1943: // LEA RDX,offset L2[RIP] 1944: genc1(cv,0x8D,(REX_W << 16) | modregrm(0,DX,5),FLconst,L2offset); 1945: genregs(cv,0x29,AX,DX); // SUB RDX,RAX 1946: code_orrex(cv, REX_W); 1947: // LEA RAX,voff+vsize-6*8-16+0x7F[RBP] 1948: unsigned ea = (REX_W << 16) | modregrm(2,AX,BPRM); 1949: if (!hasframe) 1950: // add sib byte for [RSP] addressing 1951: ea = (REX_W << 16) | (modregrm(0,4,SP) << 8) | modregxrm(2,AX,4); 1952: genc1(cv,0x8D,ea,FLconst,raxoff); 1953: gen2(cv,0xFF,modregrm(3,4,DX)); // JMP EDX 1954: for (int i = 0; i < 8; i++) 1955: { 1956: // MOVAPS -15-16*i[RAX],XMM7-i 1957: genc1(cv,0x0F29,modregrm(0,XMM7-i,0),FLconst,-15-16*i); 1958: } 1959: 1960: /* Compute offset_regs and offset_fpregs 1961: */ 1962: unsigned offset_regs = 0; 1963: unsigned offset_fpregs = vregnum * 8; 1964: for (int i = AX; i <= XMM7; i++) 1965: { regm_t m = mask[i]; 1966: if (m & namedargs) 1967: { 1968: if (m & (mDI|mSI|mDX|mCX|mR8|mR9)) 1969: offset_regs += 8; 1970: else if (m & XMMREGS) 1971: offset_fpregs += 16; 1972: namedargs &= ~m; 1973: if (!namedargs) 1974: break; 1975: } 1976: } 1977: // MOV 1[RAX],offset_regs 1978: genc(cv,0xC7,modregrm(2,0,AX),FLconst,1,FLconst,offset_regs); 1979: 1980: // MOV 5[RAX],offset_fpregs 1981: genc(cv,0xC7,modregrm(2,0,AX),FLconst,5,FLconst,offset_fpregs); 1982: 1983: // LEA RDX, Poff+Poffset[RBP] 1984: ea = modregrm(2,DX,BPRM); 1985: if (!hasframe) 1986: ea = (modregrm(0,4,SP) << 8) | modregrm(2,DX,4); 1987: Poffset = (Poffset + (REGSIZE - 1)) & ~(REGSIZE - 1); 1988: genc1(cv,0x8D,(REX_W << 16) | ea,FLconst,Poff + Poffset); 1989: 1990: // MOV 9[RAX],RDX 1991: genc1(cv,0x89,(REX_W << 16) | modregrm(2,DX,AX),FLconst,9); 1992: 1993: // SUB RAX,6*8+0x7F // point to start of __va_argsave 1994: genc2(cv,0x2D,0,6*8+0x7F); 1995: code_orrex(cv, REX_W); 1996: 1997: // MOV 6*8+8*16+4+4+8[RAX],RAX // set __va_argsave.reg_args 1998: genc1(cv,0x89,(REX_W << 16) | modregrm(2,AX,AX),FLconst,6*8+8*16+4+4+8); 1999: 2000: pinholeopt(cv, NULL); 2001: useregs(mDX|mAX); 2002: c = cat(c,cv); 2003: } 2004: } 2005: 2006: #if 0 && TARGET_LINUX 2007: if (gotref) 2008: { // position independent reference 2009: c = cat(c, cod3_load_got()); 2010: } 2011: #endif 2012: 2013: return c; 2014: } 2015: 2016: /******************************* 2017: * Generate and return function epilog. 2018: * Output: 2019: * retsize Size of function epilog 2020: */ 2021: 2022: static targ_size_t spoff; 2023: 2024: void epilog(block *b) 2025: { code *c; 2026: code *cr; 2027: code *ce; 2028: code *cpopds; 2029: unsigned reg; 2030: unsigned regx; // register that's not a return reg 2031: regm_t topop,regm; 2032: tym_t tyf,tym; 2033: int op; 2034: char farfunc; 2035: targ_size_t xlocalsize = localsize; 2036: 2037: c = CNIL; 2038: ce = b->Bcode; 2039: tyf = funcsym_p->ty(); 2040: tym = tybasic(tyf); 2041: farfunc = tyfarfunc(tym); 2042: if (!(b->Bflags & BFLepilog)) // if no epilog code 2043: goto Lret; // just generate RET 2044: regx = (b->BC == BCret) ? AX : CX; 2045: 2046: spoff = 0; 2047: retsize = 0; 2048: 2049: if (tyf & mTYnaked) // if no prolog/epilog 2050: return; 2051: 2052: if (tym == TYifunc) 2053: { static unsigned char ops2[] = { 0x07,0x1F,0x61,0xCF,0 }; 2054: static unsigned char ops0[] = { 0x07,0x1F,0x5F,0x5E, 2055: 0x5D,0x5B,0x5B,0x5A, 2056: 0x59,0x58,0xCF,0 }; 2057: unsigned char *p; 2058: 2059: c = genregs(c,0x8B,SP,BP); // MOV SP,BP 2060: p = (config.target_cpu >= TARGET_80286) ? ops2 : ops0; 2061: do 2062: gen1(c,*p); 2063: while (*++p); 2064: goto Lopt; 2065: } 2066: 2067: if (config.flags & CFGtrace && 2068: (!(config.flags4 & CFG4allcomdat) || 2069: funcsym_p->Sclass == SCcomdat || 2070: funcsym_p->Sclass == SCglobal || 2071: (config.flags2 & CFG2comdat && SymInline(funcsym_p)) 2072: ) 2073: ) 2074: { 2075: symbol *s = rtlsym[farfunc ? RTLSYM_TRACE_EPI_F : RTLSYM_TRACE_EPI_N]; 2076: makeitextern(s); 2077: c = gencs(c,I16 ? 0x9A : CALL,0,FLfunc,s); // CALLF _trace 2078: if (!I16) 2079: code_orflag(c,CFoff | CFselfrel); 2080: useregs((ALLREGS | mBP | mES) & ~s->Sregsaved); 2081: } 2082: 2083: if (usednteh & ~NTEHjmonitor && (config.exe == EX_NT || MARS)) 2084: c = cat(c,nteh_epilog()); 2085: 2086: cpopds = CNIL; 2087: if (tyf & mTYloadds) 2088: { cpopds = gen1(cpopds,0x1F); // POP DS 2089: c = cat(c,cpopds); 2090: spoff += intsize; 2091: } 2092: 2093: /* Pop all the general purpose registers saved on the stack 2094: * by the prolog code. Remember to do them in the reverse 2095: * order they were pushed. 2096: */ 2097: reg = I64 ? R15 : DI; 2098: regm = 1 << reg; 2099: topop = fregsaved & ~mfuncreg; 2100: #ifdef DEBUG 2101: if (topop & ~0xFFFF) 2102: printf("fregsaved = x%x, mfuncreg = x%x\n",fregsaved,mfuncreg); 2103: #endif 2104: assert(!(topop & ~0xFFFF)); 2105: while (topop) 2106: { if (topop & regm) 2107: { c = gen1(c,0x58 + (reg & 7)); // POP reg 2108: if (reg & 8) 2109: code_orrex(c, REX_B); 2110: topop &= ~regm; 2111: spoff += REGSIZE; 2112: } 2113: regm >>= 1; 2114: reg--; 2115: } 2116: 2117: #if MARS 2118: if (usednteh & NTEHjmonitor) 2119: { 2120: regm_t retregs = 0; 2121: if (b->BC == BCretexp) 2122: retregs = regmask(b->Belem->Ety, tym); 2123: code *cn = nteh_monitor_epilog(retregs); 2124: c = cat(c,cn); 2125: xlocalsize += 8; 2126: } 2127: #endif 2128: 2129: if (config.wflags & WFwindows && farfunc) 2130: { 2131: int wflags = config.wflags; 2132: if (wflags & WFreduced && !(tyf & mTYexport)) 2133: { // reduced prolog/epilog for non-exported functions 2134: wflags &= ~(WFdgroup | WFds | WFss); 2135: if (!(wflags & WFsaveds)) 2136: goto L4; 2137: } 2138: 2139: if (localsize | usedalloca) 2140: { 2141: c = genc1(c,0x8D,modregrm(1,SP,6),FLconst,(targ_uns)-2); /* LEA SP,-2[BP] */ 2142: } 2143: if (wflags & (WFsaveds | WFds | WFss | WFdgroup)) 2144: { if (cpopds) 2145: cpopds->Iop = NOP; // don't need previous one 2146: c = gen1(c,0x1F); // POP DS 2147: } 2148: c = gen1(c,0x58 + BP); // POP BP 2149: if (config.wflags & WFincbp) 2150: gen1(c,0x48 + BP); // DEC BP 2151: assert(hasframe); 2152: } 2153: else 2154: { 2155: if (needframe || (xlocalsize && hasframe)) 2156: { 2157: L4: 2158: assert(hasframe); 2159: if (xlocalsize | usedalloca) 2160: { if (config.target_cpu >= TARGET_80286 && 2161: !(config.target_cpu >= TARGET_80386 && 2162: config.flags4 & CFG4speed) 2163: ) 2164: c = gen1(c,0xC9); // LEAVE 2165: else if (0 && xlocalsize == REGSIZE && !usedalloca && I32) 2166: { // This doesn't work - I should figure out why 2167: mfuncreg &= ~mask[regx]; 2168: c = gen1(c,0x58 + regx); // POP regx 2169: c = gen1(c,0x58 + BP); // POP BP 2170: } 2171: else 2172: { c = genregs(c,0x8B,SP,BP); // MOV SP,BP 2173: if (I64) 2174: code_orrex(c, REX_W); // MOV RSP,RBP 2175: c = gen1(c,0x58 + BP); // POP BP 2176: } 2177: } 2178: else 2179: c = gen1(c,0x58 + BP); // POP BP 2180: if (config.wflags & WFincbp && farfunc) 2181: gen1(c,0x48 + BP); // DEC BP 2182: } 2183: else if (xlocalsize == REGSIZE && (!I16 || b->BC == BCret))
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
2184: { mfuncreg &= ~mask[regx]; 2185: c = gen1(c,0x58 + regx); // POP regx 2186: } 2187: else if (xlocalsize) 2188: { 2189: c = genc2(c,0x81,modregrm(3,0,SP),xlocalsize); // ADD SP,xlocalsize 2190: if (I64) 2191: code_orrex(c, REX_W); 2192: } 2193: } 2194: if (b->BC == BCret || b->BC == BCretexp) 2195: { 2196: Lret: 2197: op = tyfarfunc(tym) ? 0xCA : 0xC2; 2198: if (tym == TYhfunc) 2199: { 2200: c = genc2(c,0xC2,0,4); // RET 4 2201: } 2202: else if (!typfunc(tym) || // if caller cleans the stack 2203: Poffset == 0) // or nothing pushed on the stack anyway 2204: { op++; // to a regular RET 2205: c = gen1(c,op); 2206: } 2207: else 2208: { // Stack is always aligned on register size boundary 2209: Poffset = (Poffset + (REGSIZE - 1)) & ~(REGSIZE - 1); 2210: c = genc2(c,op,0,Poffset); // RET Poffset 2211: } 2212: } 2213: 2214: Lopt: 2215: // If last instruction in ce is ADD SP,imm, and first instruction 2216: // in c sets SP, we can dump the ADD. 2217: cr = code_last(ce); 2218: if (cr && c && !I64) 2219: { 2220: if (cr->Iop == 0x81 && cr->Irm == modregrm(3,0,SP)) // if ADD SP,imm 2221: { 2222: if ( 2223: c->Iop == 0xC9 || // LEAVE 2224: (c->Iop == 0x8B && c->Irm == modregrm(3,SP,BP)) || // MOV SP,BP 2225: (c->Iop == 0x8D && c->Irm == modregrm(1,SP,6)) // LEA SP,-imm[BP] 2226: ) 2227: cr->Iop = NOP; 2228: else if (c->Iop == 0x58 + BP) // if POP BP 2229: { cr->Iop = 0x8B; 2230: cr->Irm = modregrm(3,SP,BP); // MOV SP,BP 2231: } 2232: } 2233: #if 0 // These optimizations don't work if the called function 2234: // cleans off the stack. 2235: else if (c->Iop == 0xC3 && cr->Iop == CALL) // CALL near 2236: { cr->Iop = 0xE9; // JMP near 2237: c->Iop = NOP; 2238: } 2239: else if (c->Iop == 0xCB && cr->Iop == 0x9A) // CALL far 2240: { cr->Iop = 0xEA; // JMP far 2241: c->Iop = NOP; 2242: } 2243: #endif 2244: } 2245: 2246: retsize += calcblksize(c); // compute size of function epilog 2247: b->Bcode = cat(ce,c); 2248: } 2249: 2250: /******************************* 2251: * Return offset of SP from BP. 2252: */ 2253: 2254: targ_size_t cod3_spoff() 2255: { 2256: return spoff + localsize; 2257: } 2258: 2259: /********************************** 2260: * Load value of _GLOBAL_OFFSET_TABLE_ into EBX 2261: */ 2262: 2263: code *cod3_load_got() 2264: { 2265: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2266: code *c; 2267: code *cgot; 2268: 2269: c = genc2(NULL,CALL,0,0); // CALL L1 2270: gen1(c, 0x58 + BX); // L1: POP EBX 2271: 2272: // ADD EBX,_GLOBAL_OFFSET_TABLE_+3 2273: symbol *gotsym = elfobj_getGOTsym(); 2274: cgot = gencs(CNIL,0x81,0xC3,FLextern,gotsym); 2275: cgot->Iflags = CFoff; 2276: cgot->IEVoffset2 = 3; 2277: 2278: makeitextern(gotsym); 2279: return cat(c,cgot); 2280: #else 2281: assert(0); 2282: return NULL; 2283: #endif 2284: } 2285: 2286: /**************************** 2287: * Generate code for, and output a thunk. 2288: * Input: 2289: * thisty Type of this pointer 2290: * p ESP parameter offset to this pointer 2291: * d offset to add to 'this' pointer 2292: * d2 offset from 'this' to vptr 2293: * i offset into vtbl[] 2294: */ 2295: 2296: void cod3_thunk(symbol *sthunk,symbol *sfunc,unsigned p,tym_t thisty, 2297: targ_size_t d,int i,targ_size_t d2) 2298: { code *c,*c1; 2299: targ_size_t thunkoffset; 2300: tym_t thunkty; 2301: 2302: cod3_align(); 2303: 2304: /* Skip over return address */ 2305: thunkty = tybasic(sthunk->ty()); 2306: if (tyfarfunc(thunkty)) 2307: p += I32 ? 8 : tysize[TYfptr]; /* far function */ 2308: else 2309: p += tysize[TYnptr]; 2310: 2311: if (!I16) 2312: { 2313: /* 2314: Generate: 2315: ADD p[ESP],d 2316: For direct call: 2317: JMP sfunc 2318: For virtual call: 2319: MOV EAX, p[ESP] EAX = this 2320: MOV EAX, d2[EAX] EAX = this->vptr 2321: JMP i[EAX] jump to virtual function 2322: */ 2323: unsigned reg = 0; 2324: if ((targ_ptrdiff_t)d < 0) 2325: { 2326: d = -d;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
2327: reg = 5; // switch from ADD to SUB 2328: } 2329: if (thunkty == TYmfunc) 2330: { // ADD ECX,d 2331: c = CNIL; 2332: if (d) 2333: c = genc2(c,0x81,modregrm(3,reg,CX),d); 2334: } 2335: else if (thunkty == TYjfunc || (I64 && thunkty == TYnfunc)) 2336: { // ADD EAX,d 2337: c = CNIL; 2338: if (d) 2339: c = genc2(c,0x81,modregrm(3,reg,I64 ? DI : AX),d); 2340: } 2341: else 2342: { 2343: c = genc(CNIL,0x81,modregrm(2,reg,4), 2344: FLconst,p, // to this 2345: FLconst,d); // ADD p[ESP],d 2346: c->Isib = modregrm(0,4,SP); 2347: } 2348: if (I64 && c) 2349: c->Irex |= REX_W; 2350: } 2351: else 2352: { 2353: /* 2354: Generate: 2355: MOV BX,SP 2356: ADD [SS:] p[BX],d 2357: For direct call: 2358: JMP sfunc 2359: For virtual call: 2360: MOV BX, p[BX] BX = this 2361: MOV BX, d2[BX] BX = this->vptr 2362: JMP i[BX] jump to virtual function 2363: */ 2364: 2365: 2366: c = genregs(CNIL,0x89,SP,BX); /* MOV BX,SP */ 2367: c1 = genc(CNIL,0x81,modregrm(2,0,7), 2368: FLconst,p, /* to this */ 2369: FLconst,d); /* ADD p[BX],d */ 2370: if (config.wflags & WFssneds || 2371: // If DS needs reloading from SS, 2372: // then assume SS != DS on thunk entry 2373: (config.wflags & WFss && LARGEDATA)) 2374: c1->Iflags |= CFss; /* SS: */ 2375: c = cat(c,c1); 2376: } 2377: 2378: if ((i & 0xFFFF) != 0xFFFF) /* if virtual call */ 2379: { code *c2,*c3; 2380: 2381: #define FARTHIS (tysize(thisty) > REGSIZE) 2382: #define FARVPTR FARTHIS 2383: 2384: assert(thisty != TYvptr); /* can't handle this case */ 2385: 2386: if (!I16) 2387: { 2388: assert(!FARTHIS && !LARGECODE); 2389: if (thunkty == TYmfunc) // if 'this' is in ECX 2390: { c1 = CNIL; 2391: 2392: // MOV EAX,d2[ECX] 2393: c2 = genc1(CNIL,0x8B,modregrm(2,AX,CX),FLconst,d2); 2394: } 2395: else if (thunkty == TYjfunc) // if 'this' is in EAX 2396: { c1 = CNIL; 2397: 2398: // MOV EAX,d2[EAX] 2399: c2 = genc1(CNIL,0x8B,modregrm(2,AX,AX),FLconst,d2); 2400: } 2401: else 2402: { 2403: // MOV EAX,p[ESP] 2404: c1 = genc1(CNIL,0x8B,(modregrm(0,4,SP) << 8) | modregrm(2,AX,4),FLconst,(targ_uns) p); 2405: if (I64) 2406: c1->Irex |= REX_W; 2407: 2408: // MOV EAX,d2[EAX] 2409: c2 = genc1(CNIL,0x8B,modregrm(2,AX,AX),FLconst,d2); 2410: } 2411: if (I64) 2412: code_orrex(c2, REX_W); 2413: /* JMP i[EAX] */ 2414: c3 = genc1(CNIL,0xFF,modregrm(2,4,0),FLconst,(targ_uns) i); 2415: } 2416: else 2417: { 2418: /* MOV/LES BX,[SS:] p[BX] */ 2419: c1 = genc1(CNIL,(FARTHIS ? 0xC4 : 0x8B),modregrm(2,BX,7),FLconst,(targ_uns) p); 2420: if (config.wflags & WFssneds || 2421: // If DS needs reloading from SS, 2422: // then assume SS != DS on thunk entry 2423: (config.wflags & WFss && LARGEDATA)) 2424: c1->Iflags |= CFss; /* SS: */ 2425: 2426: /* MOV/LES BX,[ES:]d2[BX] */ 2427: c2 = genc1(CNIL,(FARVPTR ? 0xC4 : 0x8B),modregrm(2,BX,7),FLconst,d2); 2428: if (FARTHIS) 2429: c2->Iflags |= CFes; /* ES: */ 2430: 2431: /* JMP i[BX] */ 2432: c3 = genc1(CNIL,0xFF,modregrm(2,(LARGECODE ? 5 : 4),7),FLconst,(targ_uns) i); 2433: if (FARVPTR) 2434: c3->Iflags |= CFes; /* ES: */ 2435: } 2436: c = cat4(c,c1,c2,c3); 2437: } 2438: else 2439: { 2440: c1 = gencs(CNIL,(LARGECODE ? 0xEA : 0xE9),0,FLfunc,sfunc); /* JMP sfunc */ 2441: c1->Iflags |= LARGECODE ? (CFseg | CFoff) : (CFselfrel | CFoff); 2442: c = cat(c,c1); 2443: } 2444: 2445: thunkoffset = Coffset; 2446: pinholeopt(c,NULL); 2447: codout(c); 2448: code_free(c); 2449: 2450: sthunk->Soffset = thunkoffset; 2451: sthunk->Ssize = Coffset - thunkoffset; /* size of thunk */ 2452: sthunk->Sseg = cseg; 2453: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2454: objpubdef(cseg,sthunk,sthunk->Soffset); 2455: #endif 2456: searchfixlist(sthunk); /* resolve forward refs */ 2457: } 2458: 2459: /***************************** 2460: * Assume symbol s is extern. 2461: */ 2462: 2463: void makeitextern(symbol *s) 2464: { 2465: if (s->Sxtrnnum == 0) 2466: { s->Sclass = SCextern; /* external */ 2467: /*printf("makeitextern(x%x)\n",s);*/ 2468: objextern(s); 2469: } 2470: } 2471: 2472: 2473: /******************************* 2474: * Replace JMPs in Bgotocode with JMP SHORTs whereever possible. 2475: * This routine depends on FLcode jumps to only be forward 2476: * referenced. 2477: * BFLjmpoptdone is set to TRUE if nothing more can be done 2478: * with this block. 2479: * Input: 2480: * flag !=0 means don't have correct Boffsets yet 2481: * Returns: 2482: * number of bytes saved 2483: */ 2484: 2485: int branch(block *bl,int flag) 2486: { int bytesaved; 2487: code *c,*cn,*ct; 2488: targ_size_t offset,disp; 2489: targ_size_t csize; 2490: 2491: if (!flag) 2492: bl->Bflags |= BFLjmpoptdone; // assume this will be all 2493: c = bl->Bcode; 2494: if (!c) 2495: return 0; 2496: bytesaved = 0; 2497: offset = bl->Boffset; /* offset of start of block */ 2498: while (1) 2499: { unsigned char op; 2500: 2501: csize = calccodsize(c); 2502: cn = code_next(c); 2503: op = c->Iop; 2504: if ((op & ~0x0F) == 0x70 && c->Iflags & CFjmp16 || 2505: op == JMP) 2506: { 2507: L1: 2508: switch (c->IFL2) 2509: { 2510: case FLblock: 2511: if (flag) // no offsets yet, don't optimize 2512: goto L3; 2513: disp = c->IEV2.Vblock->Boffset - offset - csize; 2514: 2515: /* If this is a forward branch, and there is an aligned 2516: * block intervening, it is possible that shrinking 2517: * the jump instruction will cause it to be out of 2518: * range of the target. This happens if the alignment 2519: * prevents the target block from moving correspondingly 2520: * closer. 2521: */ 2522: if (disp >= 0x7F-4 && c->IEV2.Vblock->Boffset > offset) 2523: { /* Look for intervening alignment 2524: */ 2525: for (block *b = bl->Bnext; b; b = b->Bnext) 2526: { 2527: if (b->Balign) 2528: { 2529: bl->Bflags &= ~BFLjmpoptdone; // some JMPs left 2530: goto L3; 2531: } 2532: if (b == c->IEV2.Vblock) 2533: break; 2534: } 2535: } 2536: 2537: break; 2538: 2539: case FLcode: 2540: { code *cr; 2541: 2542: disp = 0; 2543: 2544: ct = c->IEV2.Vcode; /* target of branch */ 2545: assert(ct->Iflags & (CFtarg | CFtarg2)); 2546: for (cr = cn; cr; cr = code_next(cr)) 2547: { 2548: if (cr == ct) 2549: break; 2550: disp += calccodsize(cr); 2551: } 2552: 2553: if (!cr) 2554: { // Didn't find it in forward search. Try backwards jump 2555: int s = 0; 2556: disp = 0; 2557: for (cr = bl->Bcode; cr != cn; cr = code_next(cr)) 2558: { 2559: assert(cr != NULL); // must have found it 2560: if (cr == ct) 2561: s = 1; 2562: if (s) 2563: disp += calccodsize(cr); 2564: } 2565: } 2566: 2567: if (config.flags4 & CFG4optimized && !flag) 2568: { 2569: /* Propagate branch forward past junk */ 2570: while (1) 2571: { if (ct->Iop == NOP || 2572: ct->Iop == (ESCAPE | ESClinnum)) 2573: { ct = code_next(ct); 2574: if (!ct) 2575: goto L2; 2576: } 2577: else 2578: { c->IEV2.Vcode = ct; 2579: ct->Iflags |= CFtarg; 2580: break; 2581: } 2582: } 2583: 2584: /* And eliminate jmps to jmps */ 2585: if ((op == ct->Iop || ct->Iop == JMP) && 2586: (op == JMP || c->Iflags & CFjmp16)) 2587: { c->IFL2 = ct->IFL2; 2588: c->IEV2.Vcode = ct->IEV2.Vcode; 2589: /*printf("eliminating branch\n");*/ 2590: goto L1; 2591: } 2592: L2: ; 2593: } 2594: } 2595: break; 2596: 2597: default: 2598: goto L3; 2599: } 2600: 2601: if (disp == 0) // bra to next instruction 2602: { bytesaved += csize; 2603: c->Iop = NOP; // del branch instruction 2604: c->IEV2.Vcode = NULL; 2605: c = cn; 2606: if (!c) 2607: break; 2608: continue; 2609: } 2610: else if ((targ_size_t)(targ_schar)(disp - 2) == (disp - 2) && 2611: (targ_size_t)(targ_schar)disp == disp) 2612: { 2613: if (op == JMP) 2614: { c->Iop = JMPS; // JMP SHORT 2615: bytesaved += I16 ? 1 : 3; 2616: } 2617: else // else Jcond 2618: { c->Iflags &= ~CFjmp16; // a branch is ok 2619: bytesaved += I16 ? 3 : 4; 2620: 2621: // Replace a cond jump around a call to a function that 2622: // never returns with a cond jump to that function. 2623: if (config.flags4 & CFG4optimized && 2624: config.target_cpu >= TARGET_80386 && 2625: disp == (I16 ? 3 : 5) && 2626: cn && 2627: cn->Iop == CALL && 2628: cn->IFL2 == FLfunc && 2629: cn->IEVsym2->Sflags & SFLexit && 2630: !(cn->Iflags & (CFtarg | CFtarg2)) 2631: ) 2632: { 2633: cn->Iop = 0x0F00 | ((c->Iop & 0x0F) ^ 0x81); 2634: c->Iop = NOP; 2635: c->IEV2.Vcode = NULL; 2636: bytesaved++; 2637: 2638: // If nobody else points to ct, we can remove the CFtarg 2639: if (flag && ct) 2640: { code *cx; 2641: 2642: for (cx = bl->Bcode; 1; cx = code_next(cx)) 2643: { 2644: if (!cx) 2645: { ct->Iflags &= ~CFtarg; 2646: break; 2647: } 2648: if (cx->IEV2.Vcode == ct) 2649: break; 2650: } 2651: } 2652: } 2653: } 2654: csize = calccodsize(c); 2655: } 2656: else 2657: bl->Bflags &= ~BFLjmpoptdone; // some JMPs left 2658: } 2659: L3: 2660: if (cn) 2661: { offset += csize; 2662: c = cn; 2663: } 2664: else 2665: break; 2666: } 2667: //printf("bytesaved = x%x\n",bytesaved); 2668: return bytesaved; 2669: } 2670: 2671: /************************************************ 2672: * Adjust all Soffset's of stack variables so they 2673: * are all relative to the frame pointer. 2674: */ 2675: 2676: #if MARS 2677: 2678: void cod3_adjSymOffsets() 2679: { SYMIDX si; 2680: 2681: //printf("cod3_adjSymOffsets()\n"); 2682: for (si = 0; si < globsym.top; si++) 2683: { //printf("globsym.tab[%d] = %p\n",si,globsym.tab[si]); 2684: symbol *s = globsym.tab[si]; 2685: 2686: switch (s->Sclass) 2687: { 2688: case SCparameter: 2689: case SCregpar: 2690: //printf("s = '%s', Soffset = x%x, Poff = x%x, EBPtoESP = x%x\n", s->Sident, s->Soffset, Poff, EBPtoESP); 2691: s->Soffset += Poff; 2692: if (0 && !(funcsym_p->Sfunc->Fflags3 & Fmember)) 2693: { 2694: if (!hasframe) 2695: s->Soffset += EBPtoESP; 2696: if (funcsym_p->Sfunc->Fflags3 & Fnested) 2697: s->Soffset += REGSIZE; 2698: } 2699: break; 2700: case SCauto: 2701: case SCfastpar: 2702: case SCregister: 2703: case_auto:
warning C4102: 'case_auto' : unreferenced label
2704: //printf("s = '%s', Soffset = x%x, Aoff = x%x, BPoff = x%x EBPtoESP = x%x\n", s->Sident, s->Soffset, Aoff, BPoff, EBPtoESP); 2705: // if (!(funcsym_p->Sfunc->Fflags3 & Fnested)) 2706: s->Soffset += Aoff + BPoff; 2707: break; 2708: case SCbprel: 2709: break; 2710: default: 2711: continue; 2712: } 2713: #if 0 2714: if (!hasframe) 2715: s->Soffset += EBPtoESP; 2716: #endif 2717: } 2718: } 2719: 2720: #endif 2721: 2722: /******************************* 2723: * Take symbol info in union ev and replace it with a real address 2724: * in Vpointer. 2725: */ 2726: 2727: void assignaddr(block *bl) 2728: { 2729: int EBPtoESPsave = EBPtoESP; 2730: int hasframesave = hasframe; 2731: 2732: if (bl->Bflags & BFLoutsideprolog) 2733: { EBPtoESP = -REGSIZE; 2734: hasframe = 0; 2735: } 2736: assignaddrc(bl->Bcode); 2737: hasframe = hasframesave; 2738: EBPtoESP = EBPtoESPsave; 2739: } 2740: 2741: void assignaddrc(code *c) 2742: { 2743: int sn; 2744: symbol *s; 2745: unsigned char ins,rm; 2746: targ_size_t soff; 2747: targ_size_t base; 2748: 2749: base = EBPtoESP; 2750: for (; c; c = code_next(c)) 2751: { 2752: #ifdef DEBUG 2753: if (0) 2754: { printf("assignaddrc()\n"); 2755: c->print(); 2756: } 2757: if (code_next(c) && code_next(code_next(c)) == c) 2758: assert(0); 2759: #endif 2760: if ((c->Iop & 0xFFFD00) == 0x0F3800) 2761: ins = inssize2[(c->Iop >> 8) & 0xFF]; 2762: else if ((c->Iop & 0xFF00) == 0x0F00) 2763: ins = inssize2[c->Iop & 0xFF]; 2764: else if ((c->Iop & 0xFF) == ESCAPE) 2765: { 2766: if (c->Iop == (ESCAPE | ESCadjesp)) 2767: { 2768: //printf("adjusting EBPtoESP (%d) by %ld\n",EBPtoESP,c->IEV2.Vint); 2769: EBPtoESP += c->IEV2.Vint; 2770: c->Iop = NOP; 2771: } 2772: if (c->Iop == (ESCAPE | ESCframeptr)) 2773: { // Convert to load of frame pointer 2774: // c->Irm is the register to use 2775: if (hasframe) 2776: { // MOV reg,EBP 2777: c->Iop = 0x89; 2778: if (c->Irm & 8) 2779: c->Irex |= REX_B; 2780: c->Irm = modregrm(3,BP,c->Irm & 7); 2781: } 2782: else 2783: { // LEA reg,EBPtoESP[ESP] 2784: c->Iop = 0x8D; 2785: if (c->Irm & 8) 2786: c->Irex |= REX_R; 2787: c->Irm = modregrm(2,c->Irm & 7,4); 2788: c->Isib = modregrm(0,4,SP); 2789: c->Iflags = CFoff; 2790: c->IFL1 = FLconst; 2791: c->IEV1.Vuns = EBPtoESP; 2792: } 2793: } 2794: if (I64) 2795: c->Irex |= REX_W; 2796: continue; 2797: } 2798: else 2799: ins = inssize[c->Iop & 0xFF]; 2800: if (!(ins & M) || 2801: ((rm = c->Irm) & 0xC0) == 0xC0) 2802: goto do2; /* if no first operand */ 2803: if (is32bitaddr(I32,c->Iflags)) 2804: { 2805: 2806: if ( 2807: ((rm & 0xC0) == 0 && !((rm & 7) == 4 && (c->Isib & 7) == 5 || (rm & 7) == 5)) 2808: ) 2809: goto do2; /* if no first operand */ 2810: } 2811: else 2812: { 2813: if ( 2814: ((rm & 0xC0) == 0 && !((rm & 7) == 6)) 2815: ) 2816: goto do2; /* if no first operand */ 2817: } 2818: s = c->IEVsym1; 2819: switch (c->IFL1) 2820: { 2821: #if OMFOBJ 2822: case FLdata: 2823: if (s->Sclass == SCcomdat) 2824: { c->IFL1 = FLextern; 2825: goto do2; 2826: } 2827: #if MARS 2828: c->IEVseg1 = s->Sseg; 2829: #else 2830: c->IEVseg1 = DATA; 2831: #endif 2832: c->IEVpointer1 += s->Soffset; 2833: c->IFL1 = FLdatseg; 2834: goto do2; 2835: case FLudata: 2836: #if MARS 2837: c->IEVseg1 = s->Sseg; 2838: #else 2839: c->IEVseg1 = UDATA; 2840: #endif 2841: c->IEVpointer1 += s->Soffset; 2842: c->IFL1 = FLdatseg; 2843: goto do2; 2844: #else // don't loose symbol information 2845: case FLdata: 2846: case FLudata: 2847: case FLtlsdata: 2848: c->IFL1 = FLextern; 2849: goto do2; 2850: #endif 2851: case FLdatseg: 2852: c->IEVseg1 = DATA; 2853: goto do2; 2854: 2855: case FLfardata: 2856: case FLcsdata: 2857: case FLpseudo: 2858: goto do2; 2859: 2860: case FLstack: 2861: //printf("Soffset = %d, EBPtoESP = %d, base = %d, pointer = %d\n", 2862: //s->Soffset,EBPtoESP,base,c->IEVpointer1); 2863: c->IEVpointer1 += s->Soffset + EBPtoESP - base - EEoffset; 2864: break; 2865: 2866: case FLreg: 2867: case FLauto: 2868: soff = Aoff; 2869: L1: 2870: if (s->Sflags & SFLunambig && !(s->Sflags & SFLread) && // if never loaded 2871: !anyiasm && 2872: // if not optimized, leave it in for debuggability 2873: (config.flags4 & CFG4optimized || !config.fulltypes)) 2874: { c->Iop = NOP; // remove references to it 2875: continue; 2876: } 2877: if (s->Sfl == FLreg && c->IEVpointer1 < 2) 2878: { int reg = s->Sreglsw; 2879: 2880: assert(!(s->Sregm & ~mask[reg])); 2881: if (c->IEVpointer1 == 1) 2882: { assert(reg < 4); /* must be a BYTEREGS */ 2883: reg |= 4; /* convert to high byte reg */ 2884: } 2885: if (reg & 8) 2886: { assert(I64); 2887: c->Irex |= REX_B; 2888: reg &= 7; 2889: } 2890: c->Irm = (c->Irm & modregrm(0,7,0)) 2891: | modregrm(3,0,reg); 2892: assert(c->Iop != LES && c->Iop != LEA); 2893: goto do2; 2894: } 2895: else 2896: { c->IEVpointer1 += s->Soffset + soff + BPoff; 2897: if (s->Sflags & SFLunambig) 2898: c->Iflags |= CFunambig; 2899: L2: 2900: if (!hasframe) 2901: { /* Convert to ESP relative address instead of EBP */ 2902: unsigned char rm;
warning C6246: Local declaration of 'rm' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2745' of 'c:\projects\extern\d\dmd\src\backend\cod3.c': Lines: 2745
2903: 2904: assert(!I16); 2905: c->IEVpointer1 += EBPtoESP; 2906: rm = c->Irm; 2907: if ((rm & 7) == 4) // if SIB byte 2908: { 2909: assert((c->Isib & 7) == BP); 2910: assert((rm & 0xC0) != 0); 2911: c->Isib = (c->Isib & ~7) | modregrm(0,0,SP); 2912: } 2913: else 2914: { 2915: assert((rm & 7) == 5); 2916: c->Irm = (rm & modregrm(0,7,0)) 2917: | modregrm(2,0,4); 2918: c->Isib = modregrm(0,4,SP); 2919: } 2920: } 2921: } 2922: break; 2923: case FLpara: 2924: soff = Poff - BPoff; // cancel out add of BPoff 2925: goto L1; 2926: case FLtmp: 2927: soff = Toff; 2928: goto L1; 2929: case FLfltreg: 2930: c->IEVpointer1 += Foff + BPoff; 2931: c->Iflags |= CFunambig; 2932: goto L2; 2933: case FLallocatmp: 2934: c->IEVpointer1 += AAoff + BPoff; 2935: goto L2; 2936: case FLbprel: 2937: c->IEVpointer1 += s->Soffset; 2938: break; 2939: case FLcs: 2940: sn = c->IEV1.Vuns; 2941: if (!CSE_loaded(sn)) // if never loaded 2942: { c->Iop = NOP; 2943: continue; 2944: } 2945: c->IEVpointer1 = sn * REGSIZE + CSoff + BPoff; 2946: c->Iflags |= CFunambig; 2947: goto L2; 2948: case FLregsave: 2949: sn = c->IEV1.Vuns; 2950: c->IEVpointer1 = sn + regsave.off + BPoff; 2951: c->Iflags |= CFunambig; 2952: goto L2; 2953: case FLndp: 2954: #if MARS 2955: assert(c->IEV1.Vuns < NDP::savetop);
warning C4018: '<' : signed/unsigned mismatch
2956: #endif 2957: c->IEVpointer1 = c->IEV1.Vuns * NDPSAVESIZE + NDPoff + BPoff; 2958: c->Iflags |= CFunambig; 2959: goto L2; 2960: case FLoffset: 2961: break; 2962: case FLlocalsize: 2963: c->IEVpointer1 += localsize; 2964: break; 2965: case FLconst: 2966: default: 2967: goto do2; 2968: } 2969: c->IFL1 = FLconst; 2970: do2: 2971: /* Ignore TEST (F6 and F7) opcodes */ 2972: if (!(ins & T)) goto done; /* if no second operand */ 2973: s = c->IEVsym2; 2974: switch (c->IFL2) 2975: { 2976: #if ELFOBJ || MACHOBJ 2977: case FLdata: 2978: case FLudata: 2979: case FLtlsdata: 2980: c->IFL2 = FLextern; 2981: goto do2; 2982: #else 2983: case FLdata: 2984: if (s->Sclass == SCcomdat) 2985: { c->IFL2 = FLextern; 2986: goto do2; 2987: } 2988: #if MARS 2989: c->IEVseg2 = s->Sseg; 2990: #else 2991: c->IEVseg2 = DATA; 2992: #endif 2993: c->IEVpointer2 += s->Soffset; 2994: c->IFL2 = FLdatseg; 2995: goto done; 2996: case FLudata: 2997: #if MARS 2998: c->IEVseg2 = s->Sseg; 2999: #else 3000: c->IEVseg2 = UDATA; 3001: #endif 3002: c->IEVpointer2 += s->Soffset; 3003: c->IFL2 = FLdatseg; 3004: goto done; 3005: #endif 3006: case FLdatseg: 3007: c->IEVseg2 = DATA; 3008: goto done; 3009: case FLcsdata: 3010: case FLfardata: 3011: goto done; 3012: case FLreg: 3013: case FLpseudo: 3014: assert(0); 3015: /* NOTREACHED */ 3016: case FLauto: 3017: c->IEVpointer2 += s->Soffset + Aoff + BPoff; 3018: break; 3019: case FLpara: 3020: c->IEVpointer2 += s->Soffset + Poff; 3021: break; 3022: case FLtmp: 3023: c->IEVpointer2 += s->Soffset + Toff + BPoff; 3024: break; 3025: case FLfltreg: 3026: c->IEVpointer2 += Foff + BPoff; 3027: break; 3028: case FLallocatmp: 3029: c->IEVpointer2 += AAoff + BPoff; 3030: break; 3031: case FLbprel: 3032: c->IEVpointer2 += s->Soffset; 3033: break; 3034: 3035: case FLstack: 3036: c->IEVpointer2 += s->Soffset + EBPtoESP - base; 3037: break; 3038: 3039: case FLcs: 3040: case FLndp: 3041: case FLregsave: 3042: assert(0); 3043: /* NOTREACHED */ 3044: 3045: case FLconst: 3046: break; 3047: 3048: case FLlocalsize: 3049: c->IEVpointer2 += localsize; 3050: break; 3051: 3052: default: 3053: goto done; 3054: } 3055: c->IFL2 = FLconst; 3056: done: 3057: ; 3058: } 3059: } 3060: 3061: /******************************* 3062: * Return offset from BP of symbol s. 3063: */ 3064: 3065: targ_size_t cod3_bpoffset(symbol *s) 3066: { targ_size_t offset; 3067: 3068: symbol_debug(s); 3069: offset = s->Soffset; 3070: switch (s->Sfl) 3071: { 3072: case FLpara: 3073: offset += Poff; 3074: break; 3075: case FLauto: 3076: offset += Aoff + BPoff; 3077: break; 3078: case FLtmp: 3079: offset += Toff + BPoff; 3080: break; 3081: default: 3082: #ifdef DEBUG 3083: WRFL((enum FL)s->Sfl); 3084: symbol_print(s); 3085: #endif 3086: assert(0); 3087: } 3088: assert(hasframe); 3089: return offset; 3090: } 3091: 3092: 3093: /******************************* 3094: * Find shorter versions of the same instructions. 3095: * Does these optimizations: 3096: * replaces jmps to the next instruction with NOPs 3097: * sign extension of modregrm displacement 3098: * sign extension of immediate data (can't do it for OR, AND, XOR 3099: * as the opcodes are not defined) 3100: * short versions for AX EA 3101: * short versions for reg EA 3102: * Input: 3103: * b -> block for code (or NULL) 3104: */ 3105: 3106: void pinholeopt(code *c,block *b) 3107: { targ_size_t a; 3108: unsigned op,mod; 3109: unsigned char ins; 3110: int usespace; 3111: int useopsize; 3112: int space;
warning C4101: 'space' : unreferenced local variable
3113: block *bn; 3114: 3115: #ifdef DEBUG 3116: static int tested; if (!tested) { tested++; pinholeopt_unittest(); } 3117: #endif 3118: 3119: #if 0 3120: code *cstart = c; 3121: if (debugc) 3122: { 3123: printf("+pinholeopt(%p)\n",c); 3124: } 3125: #endif 3126: 3127: if (b) 3128: { bn = b->Bnext; 3129: usespace = (config.flags4 & CFG4space && b->BC != BCasm); 3130: useopsize = (I16 || (config.flags4 & CFG4space && b->BC != BCasm)); 3131: } 3132: else 3133: { bn = NULL; 3134: usespace = (config.flags4 & CFG4space); 3135: useopsize = (I16 || config.flags4 & CFG4space); 3136: } 3137: for (; c; c = code_next(c)) 3138: { 3139: L1: 3140: op = c->Iop; 3141: if ((op & 0xFFFD00) == 0x0F3800) 3142: ins = inssize2[(op >> 8) & 0xFF]; 3143: else if ((op & 0xFF00) == 0x0F00) 3144: ins = inssize2[op & 0xFF]; 3145: else 3146: ins = inssize[op & 0xFF]; 3147: if (ins & M) // if modregrm byte 3148: { int shortop = (c->Iflags & CFopsize) ? !I16 : I16; 3149: int local_BPRM = BPRM; 3150: 3151: if (c->Iflags & CFaddrsize) 3152: local_BPRM ^= 5 ^ 6; // toggle between 5 and 6 3153: 3154: unsigned rm = c->Irm; 3155: unsigned reg = rm & modregrm(0,7,0); // isolate reg field 3156: unsigned ereg = rm & 7; 3157: //printf("c = %p, op = %02x rm = %02x\n", c, op, rm); 3158: 3159: /* If immediate second operand */ 3160: if ((ins & T || op == 0xF6 || op == 0xF7) && 3161: c->IFL2 == FLconst) 3162: { 3163: int flags = c->Iflags & CFpsw; /* if want result in flags */ 3164: targ_long u = c->IEV2.Vuns; 3165: if (ins & E) 3166: u = (signed char) u; 3167: else if (shortop) 3168: u = (short) u; 3169: 3170: // Replace CMP reg,0 with TEST reg,reg 3171: if ((op & 0xFE) == 0x80 && // 80 is CMP R8,imm8; 81 is CMP reg,imm 3172: rm >= modregrm(3,7,AX) && 3173: u == 0) 3174: { c->Iop = (op & 1) | 0x84; 3175: c->Irm = modregrm(3,ereg,ereg); 3176: if (c->Irex & REX_B) 3177: c->Irex |= REX_R; 3178: goto L1; 3179: } 3180: 3181: /* Optimize ANDs with an immediate constant */ 3182: if ((op == 0x81 || op == 0x80) && reg == modregrm(0,4,0)) 3183: { 3184: if (rm >= modregrm(3,4,AX)) // AND reg,imm 3185: { 3186: if (u == 0) 3187: { /* Replace with XOR reg,reg */ 3188: c->Iop = 0x30 | (op & 1); 3189: c->Irm = modregrm(3,ereg,ereg); 3190: if (c->Irex & REX_B) 3191: c->Irex |= REX_R; 3192: goto L1; 3193: } 3194: if (u == 0xFFFFFFFF && !flags) 3195: { c->Iop = NOP; 3196: goto L1; 3197: } 3198: } 3199: if (op == 0x81 && !flags) 3200: { // If we can do the operation in one byte 3201: 3202: // If EA is not SI or DI 3203: if ((rm < modregrm(3,4,SP) || I64) && 3204: (config.flags4 & CFG4space || 3205: config.target_cpu < TARGET_PentiumPro) 3206: ) 3207: { 3208: if ((u & 0xFFFFFF00) == 0xFFFFFF00) 3209: goto L2; 3210: else if (rm < modregrm(3,0,0) || (!c->Irex && ereg < 4)) 3211: { if (!shortop) 3212: { if ((u & 0xFFFF00FF) == 0xFFFF00FF) 3213: goto L3; 3214: } 3215: else 3216: { 3217: if ((u & 0xFF) == 0xFF) 3218: goto L3; 3219: } 3220: } 3221: } 3222: if (!shortop && useopsize) 3223: { 3224: if ((u & 0xFFFF0000) == 0xFFFF0000) 3225: { c->Iflags ^= CFopsize; 3226: goto L1; 3227: } 3228: if ((u & 0xFFFF) == 0xFFFF && rm < modregrm(3,4,AX)) 3229: { c->IEVoffset1 += 2; /* address MSW */ 3230: c->IEV2.Vuns >>= 16; 3231: c->Iflags ^= CFopsize; 3232: goto L1; 3233: } 3234: if (rm >= modregrm(3,4,AX)) 3235: { 3236: if (u == 0xFF && (rm <= modregrm(3,4,BX) || I64)) 3237: { c->Iop = 0x0FB6; // MOVZX 3238: c->Irm = modregrm(3,ereg,ereg); 3239: if (c->Irex & REX_B) 3240: c->Irex |= REX_R; 3241: goto L1; 3242: } 3243: if (u == 0xFFFF) 3244: { c->Iop = 0x0FB7; // MOVZX 3245: c->Irm = modregrm(3,ereg,ereg); 3246: if (c->Irex & REX_B) 3247: c->Irex |= REX_R; 3248: goto L1; 3249: } 3250: } 3251: } 3252: } 3253: } 3254: 3255: /* Look for ADD,OR,SUB,XOR with u that we can eliminate */ 3256: if (!flags && 3257: (op == 0x81 || op == 0x80) && 3258: (reg == modregrm(0,0,0) || reg == modregrm(0,1,0) || // ADD,OR 3259: reg == modregrm(0,5,0) || reg == modregrm(0,6,0)) // SUB, XOR 3260: ) 3261: { 3262: if (u == 0) 3263: { 3264: c->Iop = NOP; 3265: goto L1; 3266: } 3267: if (u == ~0 && reg == modregrm(0,6,0)) /* XOR */ 3268: { 3269: c->Iop = 0xF6 | (op & 1); /* NOT */ 3270: c->Irm ^= modregrm(0,6^2,0); 3271: goto L1; 3272: } 3273: if (!shortop && 3274: useopsize && 3275: op == 0x81 && 3276: (u & 0xFFFF0000) == 0 && 3277: (reg == modregrm(0,6,0) || reg == modregrm(0,1,0))) 3278: { c->Iflags ^= CFopsize; 3279: goto L1; 3280: } 3281: } 3282: 3283: /* Look for TEST or OR or XOR with an immediate constant */ 3284: /* that we can replace with a byte operation */ 3285: if (op == 0xF7 && reg == modregrm(0,0,0) || 3286: op == 0x81 && reg == modregrm(0,6,0) && !flags || 3287: op == 0x81 && reg == modregrm(0,1,0)) 3288: { 3289: // See if we can replace a dword with a word 3290: // (avoid for 32 bit instructions, because CFopsize 3291: // is too slow) 3292: if (!shortop && useopsize) 3293: { if ((u & 0xFFFF0000) == 0) 3294: { c->Iflags ^= CFopsize; 3295: goto L1; 3296: } 3297: /* If memory (not register) addressing mode */ 3298: if ((u & 0xFFFF) == 0 && rm < modregrm(3,0,AX)) 3299: { c->IEVoffset1 += 2; /* address MSW */ 3300: c->IEV2.Vuns >>= 16; 3301: c->Iflags ^= CFopsize; 3302: goto L1; 3303: } 3304: } 3305: 3306: // If EA is not SI or DI 3307: if (rm < (modregrm(3,0,SP) | reg) && 3308: (usespace || 3309: config.target_cpu < TARGET_PentiumPro) 3310: ) 3311: { 3312: if ((u & 0xFFFFFF00) == 0) 3313: { 3314: L2: c->Iop--; /* to byte instruction */ 3315: c->Iflags &= ~CFopsize; 3316: goto L1; 3317: } 3318: if (((u & 0xFFFF00FF) == 0 || 3319: (shortop && (u & 0xFF) == 0)) && 3320: (rm < modregrm(3,0,0) || (!c->Irex && ereg < 4))) 3321: { 3322: L3: 3323: c->IEV2.Vuns >>= 8; 3324: if (rm >= (modregrm(3,0,AX) | reg)) 3325: c->Irm |= 4; /* AX->AH, BX->BH, etc. */ 3326: else 3327: c->IEVoffset1 += 1; 3328: goto L2; 3329: } 3330: } 3331: #if 0 3332: // BUG: which is right? 3333: else if ((u & 0xFFFF0000) == 0) 3334: #else 3335: else if (0 && op == 0xF7 && 3336: rm >= modregrm(3,0,SP) && 3337: (u & 0xFFFF0000) == 0) 3338: #endif 3339: c->Iflags &= ~CFopsize; 3340: } 3341: 3342: // Try to replace TEST reg,-1 with TEST reg,reg 3343: if (op == 0xF6 && rm >= modregrm(3,0,AX) && rm <= modregrm(3,0,7)) // TEST regL,immed8 3344: { if ((u & 0xFF) == 0xFF) 3345: { 3346: L4: c->Iop = 0x84; // TEST regL,regL 3347: c->Irm = modregrm(3,ereg,ereg); 3348: if (c->Irex & REX_B) 3349: c->Irex |= REX_R; 3350: c->Iflags &= ~CFopsize; 3351: goto L1; 3352: } 3353: } 3354: if (op == 0xF7 && rm >= modregrm(3,0,AX) && rm <= modregrm(3,0,7) && (I64 || ereg < 4)) 3355: { if (u == 0xFF) 3356: goto L4; 3357: if ((u & 0xFFFF) == 0xFF00 && shortop && !c->Irex && ereg < 4) 3358: { ereg |= 4; /* to regH */ 3359: goto L4; 3360: } 3361: } 3362: 3363: /* Look for sign extended immediate data */ 3364: if ((signed char) u == u) 3365: { 3366: if (op == 0x81) 3367: { if (reg != 0x08 && reg != 0x20 && reg != 0x30) 3368: c->Iop = op = 0x83; /* 8 bit sgn ext */ 3369: } 3370: else if (op == 0x69) /* IMUL rw,ew,dw */ 3371: c->Iop = op = 0x6B; /* IMUL rw,ew,db */ 3372: } 3373: 3374: // Look for SHIFT EA,imm8 we can replace with short form 3375: if (u == 1 && ((op & 0xFE) == 0xC0)) 3376: c->Iop |= 0xD0; 3377: 3378: } /* if immediate second operand */ 3379: 3380: /* Look for AX short form */ 3381: if (ins & A) 3382: { if (rm == modregrm(0,AX,local_BPRM) && 3383: !(c->Irex & REX_R) && // and it's AX, not R8 3384: (op & ~3) == 0x88 && 3385: !I64) 3386: { op = ((op & 3) + 0xA0) ^ 2; 3387: /* 8A-> A0 */ 3388: /* 8B-> A1 */ 3389: /* 88-> A2 */ 3390: /* 89-> A3 */ 3391: c->Iop = op; 3392: c->IFL2 = c->IFL1; 3393: c->IEV2 = c->IEV1; 3394: } 3395: 3396: /* Replace MOV REG1,REG2 with MOV EREG1,EREG2 */ 3397: else if (!I16 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3398: (op == 0x89 || op == 0x8B) && 3399: (rm & 0xC0) == 0xC0 && 3400: (!b || b->BC != BCasm) 3401: ) 3402: c->Iflags &= ~CFopsize; 3403: 3404: // If rm is AX 3405: else if ((rm & modregrm(3,0,7)) == modregrm(3,0,AX) && !(c->Irex & (REX_R | REX_B))) 3406: { switch (op) 3407: { case 0x80: op = reg | 4; break; 3408: case 0x81: op = reg | 5; break; 3409: case 0x87: op = 0x90 + (reg>>3); break; // XCHG 3410: case 0xF6: 3411: if (reg == 0) 3412: op = 0xA8; /* TEST AL,immed8 */ 3413: break; 3414: case 0xF7: 3415: if (reg == 0) 3416: op = 0xA9; /* TEST AX,immed16 */ 3417: break; 3418: } 3419: c->Iop = op; 3420: } 3421: } 3422: 3423: /* Look for reg short form */ 3424: if ((ins & R) && (rm & 0xC0) == 0xC0) 3425: { switch (op) 3426: { case 0xC6: op = 0xB0 + ereg; break; 3427: case 0xC7: op = 0xB8 + ereg; break; 3428: case 0xFF: 3429: switch (reg) 3430: { case 6<<3: op = 0x50+ereg; break;/* PUSH*/ 3431: case 0<<3: if (!I64) op = 0x40+ereg; break; /* INC*/ 3432: case 1<<3: if (!I64) op = 0x48+ereg; break; /* DEC*/ 3433: } 3434: break; 3435: case 0x8F: op = 0x58 + ereg; break; 3436: case 0x87: 3437: if (reg == 0) op = 0x90 + ereg; 3438: break; 3439: } 3440: c->Iop = op; 3441: } 3442: 3443: // Look to replace SHL reg,1 with ADD reg,reg 3444: if ((op & ~1) == 0xD0 && 3445: (rm & modregrm(3,7,0)) == modregrm(3,4,0) && 3446: config.target_cpu >= TARGET_80486) 3447: { 3448: c->Iop &= 1; 3449: c->Irm = (rm & modregrm(3,0,7)) | (ereg << 3); 3450: if (c->Irex & REX_B) 3451: c->Irex |= REX_R; 3452: if (!(c->Iflags & CFpsw) && !I16)
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3453: c->Iflags &= ~CFopsize; 3454: goto L1; 3455: } 3456: 3457: /* Look for sign extended modregrm displacement, or 0 3458: * displacement. 3459: */ 3460: 3461: if (((rm & 0xC0) == 0x80) && // it's a 16/32 bit disp 3462: c->IFL1 == FLconst) // and it's a constant 3463: { 3464: a = c->IEVpointer1; 3465: if (a == 0 && (rm & 7) != local_BPRM && // if 0[disp] 3466: !(local_BPRM == 5 && (rm & 7) == 4 && (c->Isib & 7) == BP) 3467: ) 3468: c->Irm &= 0x3F; 3469: else if (!I16) 3470: { 3471: if ((targ_size_t)(targ_schar)a == a) 3472: c->Irm ^= 0xC0; /* do 8 sx */ 3473: } 3474: else if (((targ_size_t)(targ_schar)a & 0xFFFF) == (a & 0xFFFF)) 3475: c->Irm ^= 0xC0; /* do 8 sx */ 3476: } 3477: 3478: /* Look for LEA reg,[ireg], replace with MOV reg,ireg */ 3479: else if (op == 0x8D) 3480: { rm = c->Irm & 7; 3481: mod = c->Irm & modregrm(3,0,0); 3482: if (mod == 0) 3483: { 3484: if (!I16) 3485: { 3486: switch (rm) 3487: { 3488: case 4: 3489: case 5: 3490: break; 3491: default: 3492: c->Irm |= modregrm(3,0,0); 3493: c->Iop = 0x8B; 3494: break; 3495: } 3496: } 3497: else 3498: { 3499: switch (rm) 3500: { 3501: case 4: rm = modregrm(3,0,SI); goto L6; 3502: case 5: rm = modregrm(3,0,DI); goto L6; 3503: case 7: rm = modregrm(3,0,BX); goto L6; 3504: L6: c->Irm = rm + reg; 3505: c->Iop = 0x8B; 3506: break; 3507: } 3508: } 3509: } 3510: 3511: /* replace LEA reg,0[BP] with MOV reg,BP */ 3512: else if (mod == modregrm(1,0,0) && rm == local_BPRM && 3513: c->IFL1 == FLconst && c->IEVpointer1 == 0) 3514: { c->Iop = 0x8B; /* MOV reg,BP */ 3515: c->Irm = modregrm(3,0,BP) + reg; 3516: } 3517: } 3518: 3519: // Replace [R13] with 0[R13] 3520: if (c->Irex & REX_B && (c->Irm & modregrm(3,0,5)) == modregrm(0,0,5)) 3521: { 3522: c->Irm |= modregrm(1,0,0); 3523: c->IFL1 = FLconst; 3524: c->IEVpointer1 = 0; 3525: } 3526: } 3527: else 3528: { 3529: switch (op) 3530: { 3531: default: 3532: if ((op & ~0x0F) != 0x70) 3533: break; 3534: case JMP: 3535: switch (c->IFL2) 3536: { case FLcode: 3537: if (c->IEV2.Vcode == code_next(c)) 3538: { c->Iop = NOP; 3539: continue; 3540: } 3541: break; 3542: case FLblock: 3543: if (!code_next(c) && c->IEV2.Vblock == bn) 3544: { c->Iop = NOP; 3545: continue; 3546: } 3547: break; 3548: case FLconst: 3549: case FLfunc: 3550: case FLextern: 3551: break; 3552: default: 3553: #ifdef DEBUG 3554: WRFL((enum FL)c->IFL2); 3555: #endif 3556: assert(0); 3557: } 3558: break; 3559: 3560: case 0x68: // PUSH immed16 3561: if (c->IFL2 == FLconst) 3562: { 3563: targ_long u = c->IEV2.Vuns; 3564: if (I64 || 3565: ((c->Iflags & CFopsize) ? I16 : I32)) 3566: { // PUSH 32/64 bit operand 3567: if (u == (signed char) u) 3568: c->Iop = 0x6A; // PUSH immed8 3569: } 3570: else // PUSH 16 bit operand 3571: { if ((short)u == (signed char) u) 3572: c->Iop = 0x6A; // PUSH immed8 3573: } 3574: } 3575: break; 3576: } 3577: } 3578: } 3579: #if 0 3580: if (1 || debugc) { 3581: printf("-pinholeopt(%p)\n",cstart); 3582: for (c = cstart; c; c = code_next(c)) 3583: c->print(); 3584: } 3585: #endif 3586: } 3587: 3588: #ifdef DEBUG 3589: STATIC void pinholeopt_unittest() 3590: { 3591: //printf("pinholeopt_unittest()\n"); 3592: struct CS { unsigned model,op,ea,ev1,ev2,flags; } tests[][2] = 3593: { 3594: // XOR reg,immed NOT regL 3595: {{ 16,0x81,modregrm(3,6,BX),0,0xFF,0 }, { 0,0xF6,modregrm(3,2,BX),0,0xFF }}, 3596: 3597: // MOV 0[BX],3 MOV [BX],3 3598: {{ 16,0xC7,modregrm(2,0,7),0,3}, { 0,0xC7,modregrm(0,0,7),0,3 }}, 3599: 3600: #if 0 // only if config.flags4 & CFG4space 3601: // TEST regL,immed8 3602: {{ 0,0xF6,modregrm(3,0,BX),0,0xFF,0 }, { 0,0x84,modregrm(3,BX,BX),0,0xFF }}, 3603: {{ 0,0xF7,modregrm(3,0,BX),0,0xFF,0 }, { 0,0x84,modregrm(3,BX,BX),0,0xFF }}, 3604: {{ 64,0xF6,modregrmx(3,0,R8),0,0xFF,0 }, { 0,0x84,modregxrmx(3,R8,R8),0,0xFF }}, 3605: {{ 64,0xF7,modregrmx(3,0,R8),0,0xFF,0 }, { 0,0x84,modregxrmx(3,R8,R8),0,0xFF }}, 3606: #endif 3607: 3608: // PUSH immed => PUSH immed8 3609: {{ 0,0x68,0,0,0 }, { 0,0x6A,0,0,0 }}, 3610: {{ 0,0x68,0,0,0x7F }, { 0,0x6A,0,0,0x7F }}, 3611: {{ 0,0x68,0,0,0x80 }, { 0,0x68,0,0,0x80 }}, 3612: {{ 16,0x68,0,0,0,CFopsize }, { 0,0x6A,0,0,0,CFopsize }}, 3613: {{ 16,0x68,0,0,0x7F,CFopsize }, { 0,0x6A,0,0,0x7F,CFopsize }}, 3614: {{ 16,0x68,0,0,0x80,CFopsize }, { 0,0x68,0,0,0x80,CFopsize }}, 3615: {{ 16,0x68,0,0,0x10000,0 }, { 0,0x6A,0,0,0x10000,0 }}, 3616: {{ 16,0x68,0,0,0x10000,CFopsize }, { 0,0x68,0,0,0x10000,CFopsize }}, 3617: {{ 32,0x68,0,0,0,CFopsize }, { 0,0x6A,0,0,0,CFopsize }}, 3618: {{ 32,0x68,0,0,0x7F,CFopsize }, { 0,0x6A,0,0,0x7F,CFopsize }}, 3619: {{ 32,0x68,0,0,0x80,CFopsize }, { 0,0x68,0,0,0x80,CFopsize }}, 3620: {{ 32,0x68,0,0,0x10000,CFopsize }, { 0,0x6A,0,0,0x10000,CFopsize }}, 3621: {{ 32,0x68,0,0,0x8000,CFopsize }, { 0,0x68,0,0,0x8000,CFopsize }}, 3622: }; 3623: 3624: //config.flags4 |= CFG4space; 3625: for (int i = 0; i < sizeof(tests)/sizeof(tests[0]); i++) 3626: { CS *pin = &tests[i][0]; 3627: CS *pout = &tests[i][1]; 3628: code cs; 3629: memset(&cs, 0, sizeof(cs)); 3630: if (pin->model) 3631: { 3632: if (I16 && pin->model != 16) 3633: continue; 3634: if (I32 && pin->model != 32) 3635: continue; 3636: if (I64 && pin->model != 64) 3637: continue; 3638: } 3639: //printf("[%d]\n", i); 3640: cs.Iop = pin->op; 3641: cs.Iea = pin->ea; 3642: cs.IFL1 = FLconst; 3643: cs.IFL2 = FLconst; 3644: cs.IEV1.Vuns = pin->ev1; 3645: cs.IEV2.Vuns = pin->ev2; 3646: cs.Iflags = pin->flags; 3647: pinholeopt(&cs, NULL); 3648: if (cs.Iop != pout->op) 3649: { printf("[%d] Iop = x%02x, pout = x%02x\n", i, cs.Iop, pout->op); 3650: assert(0); 3651: } 3652: assert(cs.Iea == pout->ea); 3653: assert(cs.IEV1.Vuns == pout->ev1); 3654: assert(cs.IEV2.Vuns == pout->ev2); 3655: assert(cs.Iflags == pout->flags); 3656: } 3657: } 3658: #endif 3659: 3660: /************************** 3661: * Compute jump addresses for FLcode. 3662: * Note: only works for forward referenced code. 3663: * only direct jumps and branches are detected. 3664: * LOOP instructions only work for backward refs. 3665: */ 3666: 3667: void jmpaddr(code *c) 3668: { code *ci,*cn,*ctarg,*cstart; 3669: targ_size_t ad; 3670: unsigned op; 3671: 3672: //printf("jmpaddr()\n"); 3673: cstart = c; /* remember start of code */ 3674: while (c) 3675: { 3676: op = c->Iop; 3677: if (op <= 0xEB && 3678: inssize[op] & T && // if second operand 3679: c->IFL2 == FLcode && 3680: ((op & ~0x0F) == 0x70 || op == JMP || op == JMPS || op == JCXZ || op == CALL)) 3681: { ci = code_next(c); 3682: ctarg = c->IEV2.Vcode; /* target code */ 3683: ad = 0; /* IP displacement */ 3684: while (ci && ci != ctarg) 3685: { 3686: ad += calccodsize(ci); 3687: ci = code_next(ci); 3688: } 3689: if (!ci) 3690: goto Lbackjmp; // couldn't find it 3691: if (!I16 || op == JMP || op == JMPS || op == JCXZ || op == CALL)
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
3692: c->IEVpointer2 = ad; 3693: else /* else conditional */ 3694: { if (!(c->Iflags & CFjmp16)) /* if branch */ 3695: c->IEVpointer2 = ad; 3696: else /* branch around a long jump */ 3697: { cn = code_next(c); 3698: code_next(c) = code_calloc(); 3699: code_next(code_next(c)) = cn; 3700: c->Iop = op ^ 1; /* converse jmp */ 3701: c->Iflags &= ~CFjmp16; 3702: c->IEVpointer2 = I16 ? 3 : 5; 3703: cn = code_next(c); 3704: cn->Iop = JMP; /* long jump */ 3705: cn->IFL2 = FLconst; 3706: cn->IEVpointer2 = ad; 3707: } 3708: } 3709: c->IFL2 = FLconst; 3710: } 3711: if (op == LOOP && c->IFL2 == FLcode) /* backwards refs */ 3712: { 3713: Lbackjmp: 3714: ctarg = c->IEV2.Vcode; 3715: for (ci = cstart; ci != ctarg; ci = code_next(ci)) 3716: if (!ci || ci == c) 3717: assert(0); 3718: ad = 2; /* - IP displacement */ 3719: while (ci != c) 3720: { assert(ci); 3721: ad += calccodsize(ci); 3722: ci = code_next(ci); 3723: } 3724: c->IEVpointer2 = (-ad) & 0xFF;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
3725: c->IFL2 = FLconst; 3726: } 3727: c = code_next(c); 3728: } 3729: } 3730: 3731: /******************************* 3732: * Calculate bl->Bsize. 3733: */ 3734: 3735: unsigned calcblksize(code *c) 3736: { unsigned size; 3737: 3738: for (size = 0; c; c = code_next(c)) 3739: { 3740: unsigned sz = calccodsize(c); 3741: //printf("off=%02x, sz = %d, code %p: op=%02x\n", size, sz, c, c->Iop); 3742: size += sz; 3743: } 3744: //printf("calcblksize(c = x%x) = %d\n", c, size); 3745: return size; 3746: } 3747: 3748: /***************************** 3749: * Calculate and return code size of a code. 3750: * Note that NOPs are sometimes used as markers, but are 3751: * never output. LINNUMs are never output. 3752: * Note: This routine must be fast. Profiling shows it is significant. 3753: */ 3754: 3755: unsigned calccodsize(code *c) 3756: { unsigned size; 3757: unsigned op; 3758: unsigned char rm,mod,ins; 3759: unsigned iflags; 3760: unsigned i32 = I32 || I64; 3761: unsigned a32 = i32; 3762: 3763: #ifdef DEBUG 3764: assert((a32 & ~1) == 0); 3765: #endif 3766: iflags = c->Iflags; 3767: op = c->Iop; 3768: if ((op & 0xFF00) == 0x0F00 || (op & 0xFFFD00) == 0x0F3800) 3769: op = 0x0F; 3770: else 3771: op &= 0xFF; 3772: switch (op) 3773: { 3774: case 0x0F: 3775: if ((c->Iop & 0xFFFD00) == 0x0F3800) 3776: { // 3 byte op ( 0F38-- or 0F3A-- ) 3777: ins = inssize2[(c->Iop >> 8) & 0xFF]; 3778: size = ins & 7; 3779: if (c->Iop & 0xFF000000) 3780: size++; 3781: } 3782: else 3783: { // 2 byte op ( 0F-- ) 3784: ins = inssize2[c->Iop & 0xFF]; 3785: size = ins & 7; 3786: if (c->Iop & 0xFF0000) 3787: size++; 3788: } 3789: break; 3790: 3791: case NOP: 3792: case ESCAPE: 3793: size = 0; // since these won't be output 3794: goto Lret2; 3795: 3796: case ASM: 3797: if (c->Iflags == CFaddrsize) // kludge for DA inline asm 3798: size = NPTRSIZE; 3799: else 3800: size = c->IEV1.as.len; 3801: goto Lret2; 3802: 3803: case 0xA1: 3804: case 0xA3: 3805: if (c->Irex) 3806: { 3807: size = 9; // 64 bit immediate value for MOV to/from RAX 3808: goto Lret; 3809: } 3810: goto Ldefault; 3811: 3812: case 0xF6: /* TEST mem8,immed8 */ 3813: ins = inssize[op]; 3814: size = ins & 7; 3815: if (i32) 3816: size = inssize32[op]; 3817: if ((c->Irm & (7<<3)) == 0) 3818: size++; /* size of immed8 */ 3819: break; 3820: 3821: case 0xF7: 3822: ins = inssize[op]; 3823: size = ins & 7; 3824: if (i32) 3825: size = inssize32[op]; 3826: if ((c->Irm & (7<<3)) == 0) 3827: size += (i32 ^ ((iflags & CFopsize) !=0)) ? 4 : 2; 3828: break; 3829: 3830: default: 3831: Ldefault: 3832: ins = inssize[op]; 3833: size = ins & 7; 3834: if (i32) 3835: size = inssize32[op]; 3836: } 3837: 3838: if (iflags & (CFwait | CFopsize | CFaddrsize | CFSEG)) 3839: { 3840: if (iflags & CFwait) // if add FWAIT prefix 3841: size++; 3842: if (iflags & CFSEG) // if segment override 3843: size++; 3844: 3845: // If the instruction has a second operand that is not an 8 bit, 3846: // and the operand size prefix is present, then fix the size computation 3847: // because the operand size will be different. 3848: // Walter, I had problems with this bit at the end. There can still be 3849: // an ADDRSIZE prefix for these and it does indeed change the operand size. 3850: 3851: if (iflags & (CFopsize | CFaddrsize)) 3852: { 3853: if ((ins & (T|E)) == T) 3854: { 3855: if ((op & 0xAC) == 0xA0) 3856: { 3857: if (iflags & CFaddrsize && !I64) 3858: { if (I32) 3859: size -= 2; 3860: else 3861: size += 2; 3862: } 3863: } 3864: else if (iflags & CFopsize) 3865: { if (I16) 3866: size += 2; 3867: else 3868: size -= 2; 3869: } 3870: } 3871: if (iflags & CFaddrsize) 3872: { if (!I64) 3873: a32 ^= 1; 3874: size++; 3875: } 3876: if (iflags & CFopsize) 3877: size++; /* +1 for OPSIZE prefix */ 3878: } 3879: } 3880: 3881: if ((op & ~0x0F) == 0x70) 3882: { if (iflags & CFjmp16) // if long branch 3883: size += I16 ? 3 : 4; // + 3(4) bytes for JMP 3884: } 3885: else if (ins & M) // if modregrm byte 3886: { 3887: rm = c->Irm; 3888: mod = rm & 0xC0; 3889: if (a32 || I64) 3890: { // 32 bit addressing 3891: if (issib(rm)) 3892: size++; 3893: switch (mod) 3894: { case 0: 3895: if (issib(rm) && (c->Isib & 7) == 5 || 3896: (rm & 7) == 5) 3897: size += 4; /* disp32 */ 3898: if (c->Irex & REX_B && (rm & 7) == 5) 3899: /* Instead of selecting R13, this mode is an [RIP] relative 3900: * address. Although valid, it's redundant, and should not 3901: * be generated. Instead, generate 0[R13] instead of [R13]. 3902: */ 3903: assert(0); 3904: break; 3905: case 0x40: 3906: size++; /* disp8 */ 3907: break; 3908: case 0x80: 3909: size += 4; /* disp32 */ 3910: break; 3911: } 3912: } 3913: else 3914: { // 16 bit addressing 3915: if (mod == 0x40) /* 01: 8 bit displacement */ 3916: size++; 3917: else if (mod == 0x80 || (mod == 0 && (rm & 7) == 6)) 3918: size += 2; 3919: } 3920: } 3921: 3922: Lret: 3923: if (c->Irex) 3924: { size++; 3925: if (c->Irex & REX_W && (op & ~7) == 0xB8) 3926: size += 4; 3927: } 3928: Lret2: 3929: //printf("op = x%02x, size = %d\n",op,size); 3930: return size; 3931: } 3932: 3933: /******************************** 3934: * Return !=0 if codes match. 3935: */ 3936: 3937: #if 0 3938: 3939: int code_match(code *c1,code *c2) 3940: { code cs1,cs2; 3941: unsigned char ins; 3942: 3943: if (c1 == c2) 3944: goto match; 3945: cs1 = *c1; 3946: cs2 = *c2; 3947: if (cs1.Iop != cs2.Iop) 3948: goto nomatch; 3949: switch (cs1.Iop) 3950: { 3951: case ESCAPE | ESCctor: 3952: case ESCAPE | ESCdtor: 3953: goto nomatch; 3954: 3955: case NOP: 3956: goto match; 3957: 3958: case ASM: 3959: if (cs1.IEV1.as.len == cs2.IEV1.as.len && 3960: memcmp(cs1.IEV1.as.bytes,cs2.IEV1.as.bytes,cs1.EV1.as.len) == 0) 3961: goto match; 3962: else 3963: goto nomatch; 3964: 3965: default: 3966: if ((cs1.Iop & 0xFF) == ESCAPE) 3967: goto match; 3968: break; 3969: } 3970: if (cs1.Iflags != cs2.Iflags) 3971: goto nomatch; 3972: 3973: ins = inssize[cs1.Iop & 0xFF]; 3974: if ((cs1.Iop & 0xFFFD00) == 0x0F3800) 3975: { 3976: ins = inssize2[(cs1.Iop >> 8) & 0xFF]; 3977: } 3978: else if ((cs1.Iop & 0xFF00) == 0x0F00) 3979: { 3980: ins = inssize2[cs1.Iop & 0xFF]; 3981: } 3982: 3983: if (ins & M) // if modregrm byte 3984: { 3985: if (cs1.Irm != cs2.Irm) 3986: goto nomatch; 3987: if ((cs1.Irm & 0xC0) == 0xC0) 3988: goto do2; 3989: if (is32bitaddr(I32,cs1.Iflags)) 3990: { 3991: if (issib(cs1.Irm) && cs1.Isib != cs2.Isib) 3992: goto nomatch; 3993: if ( 3994: ((rm & 0xC0) == 0 && !((rm & 7) == 4 && (c->Isib & 7) == 5 || (rm & 7) == 5)) 3995: ) 3996: goto do2; /* if no first operand */ 3997: } 3998: else 3999: { 4000: if ( 4001: ((rm & 0xC0) == 0 && !((rm & 7) == 6)) 4002: ) 4003: goto do2; /* if no first operand */ 4004: } 4005: if (cs1.IFL1 != cs2.IFL1) 4006: goto nomatch; 4007: if (flinsymtab[cs1.IFL1] && cs1.IEVsym1 != cs2.IEVsym1) 4008: goto nomatch; 4009: if (cs1.IEVoffset1 != cs2.IEVoffset1) 4010: goto nomatch; 4011: } 4012: 4013: do2: 4014: if (!(ins & T)) // if no second operand 4015: goto match; 4016: if (cs1.IFL2 != cs2.IFL2) 4017: goto nomatch; 4018: if (flinsymtab[cs1.IFL2] && cs1.IEVsym2 != cs2.IEVsym2) 4019: goto nomatch; 4020: if (cs1.IEVoffset2 != cs2.IEVoffset2) 4021: goto nomatch; 4022: 4023: match: 4024: return 1; 4025: 4026: nomatch: 4027: return 0; 4028: } 4029: 4030: #endif 4031: 4032: /************************** 4033: * Write code to intermediate file. 4034: * Code starts at offset. 4035: * Returns: 4036: * addr of end of code 4037: */ 4038: 4039: static targ_size_t offset; /* to save code use a global */ 4040: static char bytes[100]; 4041: static char *pgen; 4042: 4043: #define GEN(c) (*pgen++ = (c)) 4044: #define GENP(n,p) (memcpy(pgen,(p),(n)), pgen += (n)) 4045: #if ELFOBJ || MACHOBJ 4046: #define FLUSH() if (pgen-bytes) cod3_flush() 4047: #else 4048: #define FLUSH() ((pgen - bytes) && (cod3_flush(),0)) 4049: #endif 4050: #define OFFSET() (offset + (pgen - bytes)) 4051: 4052: STATIC void cod3_flush() 4053: { 4054: // Emit accumulated bytes to code segment 4055: #ifdef DEBUG 4056: assert(pgen - bytes < sizeof(bytes)); 4057: #endif 4058: offset += obj_bytes(cseg,offset,pgen - bytes,bytes); 4059: pgen = bytes; 4060: } 4061: 4062: unsigned codout(code *c) 4063: { unsigned op; 4064: unsigned char rm,mod;
warning C4101: 'mod' : unreferenced local variable
4065: unsigned char ins; 4066: code *cn; 4067: unsigned flags; 4068: symbol *s; 4069: 4070: #ifdef DEBUG 4071: if (debugc) printf("codout(%p), Coffset = x%llx\n",c,(unsigned long long)Coffset); 4072: #endif 4073: 4074: pgen = bytes; 4075: offset = Coffset; 4076: for (; c; c = code_next(c)) 4077: { 4078: #ifdef DEBUG 4079: if (debugc) { printf("off=%02lx, sz=%ld, ",(long)OFFSET(),(long)calccodsize(c)); c->print(); } 4080: unsigned startoffset = OFFSET(); 4081: #endif 4082: op = c->Iop; 4083: ins = inssize[op & 0xFF]; 4084: switch (op & 0xFF) 4085: { case ESCAPE: 4086: /* Check for SSE4 opcode pmaxuw xmm1,xmm2/m128 */ 4087: if(op == 0x660F383E) break; 4088: 4089: switch (op & 0xFFFF00) 4090: { case ESClinnum: 4091: /* put out line number stuff */ 4092: objlinnum(c->IEV2.Vsrcpos,OFFSET()); 4093: break; 4094: #if SCPP 4095: #if 1 4096: case ESCctor: 4097: case ESCdtor: 4098: case ESCoffset: 4099: if (config.exe != EX_NT) 4100: except_pair_setoffset(c,OFFSET() - funcoffset); 4101: break; 4102: case ESCmark: 4103: case ESCrelease: 4104: case ESCmark2: 4105: case ESCrelease2: 4106: break; 4107: #else 4108: case ESCctor: 4109: except_push(OFFSET() - funcoffset,c->IEV1.Vtor,NULL); 4110: break; 4111: case ESCdtor: 4112: except_pop(OFFSET() - funcoffset,c->IEV1.Vtor,NULL); 4113: break; 4114: case ESCmark: 4115: except_mark(); 4116: break; 4117: case ESCrelease: 4118: except_release(); 4119: break; 4120: #endif 4121: #endif 4122: } 4123: #ifdef DEBUG 4124: assert(calccodsize(c) == 0); 4125: #endif 4126: continue; 4127: case NOP: /* don't send them out */ 4128: if (op != NOP) 4129: break; 4130: #ifdef DEBUG 4131: assert(calccodsize(c) == 0); 4132: #endif 4133: continue; 4134: case ASM: 4135: if (op != ASM) 4136: break; 4137: FLUSH(); 4138: if (c->Iflags == CFaddrsize) // kludge for DA inline asm 4139: { 4140: do32bit(FLblockoff,&c->IEV1,0); 4141: } 4142: else 4143: { 4144: offset += obj_bytes(cseg,offset,c->IEV1.as.len,c->IEV1.as.bytes); 4145: } 4146: #ifdef DEBUG 4147: assert(calccodsize(c) == c->IEV1.as.len); 4148: #endif 4149: continue; 4150: } 4151: flags = c->Iflags; 4152: 4153: // See if we need to flush (don't have room for largest code sequence) 4154: if (pgen - bytes > sizeof(bytes) - (1+4+4+8+8)) 4155: FLUSH(); 4156: 4157: // see if we need to put out prefix bytes 4158: if (flags & (CFwait | CFPREFIX | CFjmp16)) 4159: { int override; 4160: 4161: if (flags & CFwait) 4162: GEN(0x9B); // FWAIT
warning C4309: '=' : truncation of constant value
4163: /* ? SEGES : SEGSS */ 4164: switch (flags & CFSEG) 4165: { case CFes: override = SEGES; goto segover; 4166: case CFss: override = SEGSS; goto segover; 4167: case CFcs: override = SEGCS; goto segover; 4168: case CFds: override = SEGDS; goto segover; 4169: case CFfs: override = SEGFS; goto segover; 4170: case CFgs: override = SEGGS; goto segover; 4171: segover: GEN(override); 4172: break; 4173: } 4174: 4175: if (flags & CFaddrsize) 4176: GEN(0x67); 4177: 4178: // Do this last because of instructions like ADDPD 4179: if (flags & CFopsize) 4180: GEN(0x66); /* operand size */ 4181: 4182: if ((op & ~0x0F) == 0x70 && flags & CFjmp16) /* long condit jmp */ 4183: { 4184: if (!I16) 4185: { // Put out 16 bit conditional jump 4186: c->Iop = op = 0x0F00 | (0x80 | (op & 0x0F)); 4187: } 4188: else 4189: { 4190: cn = code_calloc(); 4191: /*cxcalloc++;*/ 4192: code_next(cn) = code_next(c); 4193: code_next(c) = cn; // link into code 4194: cn->Iop = JMP; // JMP block 4195: cn->IFL2 = c->IFL2; 4196: cn->IEV2.Vblock = c->IEV2.Vblock; 4197: c->Iop = op ^= 1; // toggle condition 4198: c->IFL2 = FLconst; 4199: c->IEVpointer2 = I16 ? 3 : 5; // skip over JMP block 4200: c->Iflags &= ~CFjmp16; 4201: } 4202: } 4203: } 4204: 4205: if (op > 0xFF) 4206: { 4207: if ((op & 0xFFFD00) == 0x0F3800) 4208: ins = inssize2[(op >> 8) & 0xFF]; 4209: else if ((op & 0xFF00) == 0x0F00) 4210: ins = inssize2[op & 0xFF]; 4211: 4212: if (op & 0xFF000000) 4213: { 4214: unsigned char op1 = op >> 24; 4215: if (op1 == 0xF2 || op1 == 0xF3 || op1 == 0x66) 4216: { 4217: GEN(op1); 4218: if (c->Irex) 4219: GEN(c->Irex | REX); 4220: } 4221: else 4222: { 4223: if (c->Irex) 4224: GEN(c->Irex | REX); 4225: GEN(op1); 4226: } 4227: GEN((op >> 16) & 0xFF); 4228: GEN((op >> 8) & 0xFF); 4229: GEN(op & 0xFF); 4230: } 4231: else if (op & 0xFF0000) 4232: { 4233: unsigned char op1 = op >> 16; 4234: if (op1 == 0xF2 || op1 == 0xF3 || op1 == 0x66) 4235: { 4236: GEN(op1); 4237: if (c->Irex) 4238: GEN(c->Irex | REX); 4239: } 4240: else 4241: { 4242: if (c->Irex) 4243: GEN(c->Irex | REX); 4244: GEN(op1); 4245: } 4246: GEN((op >> 8) & 0xFF); 4247: GEN(op & 0xFF); 4248: } 4249: else 4250: { 4251: if (c->Irex) 4252: GEN(c->Irex | REX); 4253: GEN((op >> 8) & 0xFF); 4254: GEN(op & 0xFF); 4255: } 4256: } 4257: else 4258: { 4259: if (c->Irex) 4260: GEN(c->Irex | REX); 4261: GEN(op); 4262: } 4263: if (ins & M) /* if modregrm byte */ 4264: { 4265: rm = c->Irm; 4266: GEN(rm); 4267: 4268: // Look for an address size override when working with the 4269: // MOD R/M and SIB bytes 4270: 4271: if (is32bitaddr( I32, flags)) 4272: { 4273: if (issib(rm)) 4274: GEN(c->Isib); 4275: switch (rm & 0xC0) 4276: { case 0x40: 4277: do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 4278: break; 4279: case 0: 4280: if (!(issib(rm) && (c->Isib & 7) == 5 || 4281: (rm & 7) == 5)) 4282: break; 4283: case 0x80: 4284: { int flags = CFoff;
warning C6246: Local declaration of 'flags' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4067' of 'c:\projects\extern\d\dmd\src\backend\cod3.c': Lines: 4067
4285: targ_size_t val = 0; 4286: if (I64) 4287: { 4288: if ((rm & modregrm(3,0,7)) == modregrm(0,0,5)) // if disp32[RIP] 4289: { flags |= CFpc32; 4290: val = -4; 4291: unsigned reg = rm & modregrm(0,7,0); 4292: if (ins & T || 4293: ((op == 0xF6 || op == 0xF7) && (reg == modregrm(0,0,0) || reg == modregrm(0,1,0)))) 4294: { if (ins & E) 4295: val = -5; 4296: else if (c->Iflags & CFopsize) 4297: val = -6; 4298: else 4299: val = -8; 4300: } 4301: } 4302: } 4303: do32bit((enum FL)c->IFL1,&c->IEV1,flags,val); 4304: break; 4305: } 4306: } 4307: } 4308: else 4309: { 4310: switch (rm & 0xC0) 4311: { case 0x40: 4312: do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 4313: break; 4314: case 0: 4315: if ((rm & 7) != 6) 4316: break; 4317: case 0x80: 4318: do16bit((enum FL)c->IFL1,&c->IEV1,CFoff); 4319: break; 4320: } 4321: } 4322: } 4323: else 4324: { 4325: if (op == 0xC8) 4326: do16bit((enum FL)c->IFL1,&c->IEV1,0); 4327: } 4328: flags &= CFseg | CFoff | CFselfrel; 4329: if (ins & T) /* if second operand */ 4330: { if (ins & E) /* if data-8 */ 4331: do8bit((enum FL) c->IFL2,&c->IEV2); 4332: else if (!I16) 4333: { 4334: switch (op) 4335: { case 0xC2: /* RETN imm16 */ 4336: case 0xCA: /* RETF imm16 */ 4337: do16: 4338: do16bit((enum FL)c->IFL2,&c->IEV2,flags); 4339: break; 4340: 4341: case 0xA1: 4342: case 0xA3: 4343: if (I64 && c->Irex) 4344: { 4345: do64: 4346: do64bit((enum FL)c->IFL2,&c->IEV2,flags); 4347: break; 4348: } 4349: case 0xA0: /* MOV AL,byte ptr [] */ 4350: case 0xA2: 4351: if (c->Iflags & CFaddrsize && !I64) 4352: goto do16; 4353: else 4354: do32: 4355: do32bit((enum FL)c->IFL2,&c->IEV2,flags); 4356: break; 4357: case 0x9A: 4358: case 0xEA: 4359: if (c->Iflags & CFopsize) 4360: goto ptr1616; 4361: else 4362: goto ptr1632; 4363: 4364: case 0x68: // PUSH immed32 4365: if ((enum FL)c->IFL2 == FLblock) 4366: { 4367: c->IFL2 = FLblockoff; 4368: goto do32; 4369: } 4370: else 4371: goto case_default; 4372: 4373: case CALL: // CALL rel 4374: case JMP: // JMP rel 4375: flags |= CFselfrel; 4376: goto case_default; 4377: 4378: default: 4379: if ((op|0xF) == 0x0F8F) // Jcc rel16 rel32 4380: flags |= CFselfrel; 4381: if (I64 && (op & ~7) == 0xB8 && c->Irex & REX_W) 4382: goto do64; 4383: case_default: 4384: if (c->Iflags & CFopsize) 4385: goto do16; 4386: else 4387: goto do32; 4388: break; 4389: } 4390: } 4391: else 4392: { 4393: switch (op) { 4394: case 0xC2: 4395: case 0xCA: 4396: goto do16; 4397: case 0xA0: 4398: case 0xA1: 4399: case 0xA2: 4400: case 0xA3: 4401: if (c->Iflags & CFaddrsize) 4402: goto do32; 4403: else 4404: goto do16; 4405: break; 4406: case 0x9A: 4407: case 0xEA: 4408: if (c->Iflags & CFopsize) 4409: goto ptr1632; 4410: else 4411: goto ptr1616; 4412: 4413: ptr1616: 4414: ptr1632: 4415: //assert(c->IFL2 == FLfunc); 4416: FLUSH(); 4417: if (c->IFL2 == FLdatseg) 4418: { 4419: reftodatseg(cseg,offset,c->IEVpointer2, 4420: c->IEVseg2,flags); 4421: offset += 4; 4422: } 4423: else 4424: { 4425: s = c->IEVsym2; 4426: offset += reftoident(cseg,offset,s,0,flags); 4427: } 4428: break; 4429: 4430: case 0x68: // PUSH immed16 4431: if ((enum FL)c->IFL2 == FLblock) 4432: { c->IFL2 = FLblockoff; 4433: goto do16; 4434: } 4435: else 4436: goto case_default16; 4437: 4438: case CALL: 4439: case JMP: 4440: flags |= CFselfrel; 4441: default: 4442: case_default16: 4443: if (c->Iflags & CFopsize) 4444: goto do32; 4445: else 4446: goto do16; 4447: break; 4448: } 4449: } 4450: } 4451: else if (op == 0xF6) /* TEST mem8,immed8 */ 4452: { if ((rm & (7<<3)) == 0) 4453: do8bit((enum FL)c->IFL2,&c->IEV2); 4454: } 4455: else if (op == 0xF7) 4456: { if ((rm & (7<<3)) == 0) /* TEST mem16/32,immed16/32 */ 4457: { 4458: if ((I32 || I64) ^ ((c->Iflags & CFopsize) != 0)) 4459: do32bit((enum FL)c->IFL2,&c->IEV2,flags); 4460: else 4461: do16bit((enum FL)c->IFL2,&c->IEV2,flags); 4462: } 4463: } 4464: #ifdef DEBUG 4465: if (OFFSET() - startoffset != calccodsize(c)) 4466: { 4467: printf("actual: %d, calc: %d\n", (int)(OFFSET() - startoffset), (int)calccodsize(c)); 4468: c->print(); 4469: assert(0); 4470: } 4471: #endif 4472: } 4473: FLUSH(); 4474: Coffset = offset; 4475: //printf("-codout(), Coffset = x%x\n", Coffset); 4476: return offset; /* ending address */ 4477: } 4478: 4479: 4480: STATIC void do64bit(enum FL fl,union evc *uev,int flags) 4481: { char *p;
warning C4101: 'p' : unreferenced local variable
4482: symbol *s; 4483: targ_size_t ad; 4484: long tmp;
warning C4101: 'tmp' : unreferenced local variable
4485: 4486: assert(I64); 4487: switch (fl) 4488: { 4489: case FLconst: 4490: ad = * (targ_size_t *) uev; 4491: L1: 4492: GENP(8,&ad); 4493: return; 4494: case FLdatseg: 4495: FLUSH(); 4496: reftodatseg(cseg,offset,uev->_EP.Vpointer,uev->_EP.Vseg,CFoffset64 | flags); 4497: break; 4498: case FLframehandler: 4499: framehandleroffset = OFFSET(); 4500: ad = 0; 4501: goto L1; 4502: case FLswitch: 4503: FLUSH(); 4504: ad = uev->Vswitch->Btableoffset; 4505: if (config.flags & CFGromable) 4506: reftocodseg(cseg,offset,ad); 4507: else 4508: reftodatseg(cseg,offset,ad,JMPSEG,CFoff); 4509: break; 4510: case FLcsdata: 4511: case FLfardata: 4512: #if DEBUG 4513: symbol_print(uev->sp.Vsym); 4514: #endif 4515: assert(!TARGET_FLAT); 4516: // NOTE: In ELFOBJ all symbol refs have been tagged FLextern 4517: // strings and statics are treated like offsets from a 4518: // un-named external with is the start of .rodata or .data 4519: case FLextern: /* external data symbol */ 4520: case FLtlsdata: 4521: #if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 4522: case FLgot: 4523: case FLgotoff: 4524: #endif 4525: FLUSH(); 4526: s = uev->sp.Vsym; /* symbol pointer */ 4527: reftoident(cseg,offset,s,uev->sp.Voffset,CFoffset64 | flags); 4528: break; 4529: 4530: #if TARGET_OSX 4531: case FLgot: 4532: funcsym_p->Slocalgotoffset = OFFSET(); 4533: ad = 0; 4534: goto L1; 4535: #endif 4536: 4537: case FLfunc: /* function call */ 4538: s = uev->sp.Vsym; /* symbol pointer */ 4539: assert(!(TARGET_FLAT && tyfarfunc(s->ty()))); 4540: FLUSH(); 4541: reftoident(cseg,offset,s,0,CFoffset64 | flags); 4542: break; 4543: 4544: case FLblock: /* displacement to another block */ 4545: ad = uev->Vblock->Boffset - OFFSET() - 4; 4546: //printf("FLblock: funcoffset = %x, OFFSET = %x, Boffset = %x, ad = %x\n", funcoffset, OFFSET(), uev->Vblock->Boffset, ad); 4547: goto L1; 4548: 4549: case FLblockoff: 4550: FLUSH(); 4551: assert(uev->Vblock); 4552: //printf("FLblockoff: offset = %x, Boffset = %x, funcoffset = %x\n", offset, uev->Vblock->Boffset, funcoffset); 4553: reftocodseg(cseg,offset,uev->Vblock->Boffset); 4554: break; 4555: 4556: default: 4557: #ifdef DEBUG 4558: WRFL(fl); 4559: #endif 4560: assert(0); 4561: } 4562: offset += 8; 4563: } 4564: 4565: 4566: STATIC void do32bit(enum FL fl,union evc *uev,int flags, targ_size_t val) 4567: { char *p;
warning C4101: 'p' : unreferenced local variable
4568: symbol *s; 4569: targ_size_t ad; 4570: long tmp;
warning C4101: 'tmp' : unreferenced local variable
4571: 4572: //printf("do32bit(flags = x%x)\n", flags); 4573: switch (fl) 4574: { 4575: case FLconst: 4576: assert(sizeof(targ_size_t) == 4 || sizeof(targ_size_t) == 8); 4577: ad = * (targ_size_t *) uev; 4578: L1: 4579: GENP(4,&ad); 4580: return; 4581: case FLdatseg: 4582: FLUSH(); 4583: reftodatseg(cseg,offset,uev->_EP.Vpointer,uev->_EP.Vseg,flags); 4584: break; 4585: #if 0 4586: case FLcsdata: 4587: FLUSH(); 4588: reftocodseg(cseg,offset,uev->Vpointer); 4589: break; 4590: #endif 4591: case FLframehandler: 4592: framehandleroffset = OFFSET(); 4593: ad = 0; 4594: goto L1; 4595: case FLswitch: 4596: FLUSH(); 4597: ad = uev->Vswitch->Btableoffset; 4598: if (config.flags & CFGromable) 4599: reftocodseg(cseg,offset,ad); 4600: else 4601: reftodatseg(cseg,offset,ad,JMPSEG,CFoff); 4602: break; 4603: case FLcsdata: 4604: case FLfardata: 4605: #if DEBUG 4606: symbol_print(uev->sp.Vsym); 4607: #endif 4608: assert(!TARGET_FLAT); 4609: // NOTE: In ELFOBJ all symbol refs have been tagged FLextern 4610: // strings and statics are treated like offsets from a 4611: // un-named external with is the start of .rodata or .data 4612: case FLextern: /* external data symbol */ 4613: case FLtlsdata: 4614: #if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 4615: case FLgot: 4616: case FLgotoff: 4617: #endif 4618: FLUSH(); 4619: s = uev->sp.Vsym; /* symbol pointer */ 4620: reftoident(cseg,offset,s,uev->sp.Voffset + val,flags); 4621: break; 4622: 4623: #if TARGET_OSX 4624: case FLgot: 4625: funcsym_p->Slocalgotoffset = OFFSET(); 4626: ad = 0; 4627: goto L1; 4628: #endif 4629: 4630: case FLfunc: /* function call */ 4631: s = uev->sp.Vsym; /* symbol pointer */ 4632: #if !TARGET_FLAT 4633: if (tyfarfunc(s->ty())) 4634: { /* Large code references are always absolute */ 4635: FLUSH(); 4636: offset += reftoident(cseg,offset,s,0,flags) - 4; 4637: } 4638: else if (s->Sseg == cseg && 4639: (s->Sclass == SCstatic || s->Sclass == SCglobal) && 4640: s->Sxtrnnum == 0 && flags & CFselfrel) 4641: { /* if we know it's relative address */ 4642: ad = s->Soffset - OFFSET() - 4; 4643: goto L1; 4644: } 4645: else 4646: #endif 4647: { 4648: assert(!(TARGET_FLAT && tyfarfunc(s->ty()))); 4649: FLUSH(); 4650: reftoident(cseg,offset,s,val,flags); 4651: } 4652: break; 4653: 4654: case FLblock: /* displacement to another block */ 4655: ad = uev->Vblock->Boffset - OFFSET() - 4; 4656: //printf("FLblock: funcoffset = %x, OFFSET = %x, Boffset = %x, ad = %x\n", funcoffset, OFFSET(), uev->Vblock->Boffset, ad); 4657: goto L1; 4658: 4659: case FLblockoff: 4660: FLUSH(); 4661: assert(uev->Vblock); 4662: //printf("FLblockoff: offset = %x, Boffset = %x, funcoffset = %x\n", offset, uev->Vblock->Boffset, funcoffset); 4663: reftocodseg(cseg,offset,uev->Vblock->Boffset); 4664: break; 4665: 4666: default: 4667: #ifdef DEBUG 4668: WRFL(fl); 4669: #endif 4670: assert(0); 4671: } 4672: offset += 4; 4673: } 4674: 4675: 4676: STATIC void do16bit(enum FL fl,union evc *uev,int flags) 4677: { char *p;
warning C4101: 'p' : unreferenced local variable
4678: symbol *s; 4679: targ_size_t ad; 4680: 4681: switch (fl) 4682: { 4683: case FLconst: 4684: GENP(2,(char *) uev); 4685: return; 4686: case FLdatseg: 4687: FLUSH(); 4688: reftodatseg(cseg,offset,uev->_EP.Vpointer,uev->_EP.Vseg,flags); 4689: break; 4690: #if 0 4691: case FLcsdata: 4692: FLUSH(); 4693: reftocodseg(cseg,offset,uev->Vpointer); 4694: break; 4695: #endif 4696: case FLswitch: 4697: FLUSH(); 4698: ad = uev->Vswitch->Btableoffset; 4699: if (config.flags & CFGromable) 4700: reftocodseg(cseg,offset,ad); 4701: else 4702: reftodatseg(cseg,offset,ad,JMPSEG,CFoff); 4703: break; 4704: case FLcsdata: 4705: case FLfardata: 4706: case FLextern: /* external data symbol */ 4707: case FLtlsdata: 4708: assert(SIXTEENBIT || !TARGET_FLAT); 4709: FLUSH(); 4710: s = uev->sp.Vsym; /* symbol pointer */ 4711: reftoident(cseg,offset,s,uev->sp.Voffset,flags); 4712: break; 4713: case FLfunc: /* function call */ 4714: assert(SIXTEENBIT || !TARGET_FLAT); 4715: s = uev->sp.Vsym; /* symbol pointer */ 4716: if (tyfarfunc(s->ty())) 4717: { /* Large code references are always absolute */ 4718: FLUSH(); 4719: offset += reftoident(cseg,offset,s,0,flags) - 2; 4720: } 4721: else if (s->Sseg == cseg && 4722: (s->Sclass == SCstatic || s->Sclass == SCglobal) && 4723: s->Sxtrnnum == 0 && flags & CFselfrel) 4724: { /* if we know it's relative address */ 4725: ad = s->Soffset - OFFSET() - 2; 4726: goto L1; 4727: } 4728: else 4729: { FLUSH(); 4730: reftoident(cseg,offset,s,0,flags); 4731: } 4732: break; 4733: case FLblock: /* displacement to another block */ 4734: ad = uev->Vblock->Boffset - OFFSET() - 2; 4735: L1: 4736: GENP(2,&ad); // displacement 4737: return; 4738: 4739: case FLblockoff: 4740: FLUSH(); 4741: reftocodseg(cseg,offset,uev->Vblock->Boffset); 4742: break; 4743: 4744: default: 4745: #ifdef DEBUG 4746: WRFL(fl); 4747: #endif 4748: assert(0); 4749: } 4750: offset += 2; 4751: } 4752: 4753: STATIC void do8bit(enum FL fl,union evc *uev) 4754: { char c; 4755: 4756: switch (fl) 4757: { 4758: case FLconst: 4759: c = uev->Vuns; 4760: break; 4761: case FLblock: 4762: c = uev->Vblock->Boffset - OFFSET() - 1; 4763: #ifdef DEBUG 4764: assert(uev->Vblock->Boffset > OFFSET() || c != 0x7F); 4765: #endif 4766: break; 4767: default: 4768: #ifdef DEBUG 4769: fprintf(stderr,"fl = %d\n",fl); 4770: #endif 4771: assert(0); 4772: } 4773: GEN(c); 4774: } 4775: 4776: 4777: /**************************** 4778: * Add to the fix list. 4779: */ 4780: 4781: void addtofixlist(symbol *s,targ_size_t soffset,int seg,targ_size_t val,int flags) 4782: { fixlist *ln; 4783: static char zeros[8]; 4784: int numbytes; 4785: 4786: //printf("addtofixlist(%p '%s')\n",s,s->Sident); 4787: assert(flags); 4788: ln = (fixlist *) mem_calloc(sizeof(fixlist)); 4789: //ln->Lsymbol = s; 4790: ln->Loffset = soffset; 4791: ln->Lseg = seg; 4792: ln->Lflags = flags; 4793: ln->Lval = val; 4794: #if TARGET_OSX 4795: ln->Lfuncsym = funcsym_p; 4796: #endif 4797: 4798: if (!fixlist::start) 4799: fixlist::start = new AArray(&ti_pvoid, sizeof(fixlist *)); 4800: fixlist **pv = (fixlist **)fixlist::start->get(&s); 4801: ln->Lnext = *pv; 4802: *pv = ln; 4803: 4804: #if TARGET_FLAT 4805: numbytes = tysize[TYnptr]; 4806: if (I64 && !(flags & CFoffset64)) 4807: numbytes = 4; 4808: assert(!(flags & CFseg)); 4809: #else 4810: switch (flags & (CFoff | CFseg)) 4811: { 4812: case CFoff: numbytes = tysize[TYnptr]; break; 4813: case CFseg: numbytes = 2; break; 4814: case CFoff | CFseg: numbytes = tysize[TYfptr]; break; 4815: default: assert(0); 4816: } 4817: #endif 4818: #ifdef DEBUG 4819: assert(numbytes <= sizeof(zeros)); 4820: #endif 4821: obj_bytes(seg,soffset,numbytes,zeros); 4822: } 4823: 4824: /**************************** 4825: * Given a function symbol we've just defined the offset for, 4826: * search for it in the fixlist, and resolve any matches we find. 4827: * Input: 4828: * s function symbol just defined 4829: */ 4830: 4831: void searchfixlist(symbol *s) 4832: { 4833: //printf("searchfixlist(%s)\n",s->Sident); 4834: if (fixlist::start) 4835: { 4836: fixlist **lp = (fixlist **)fixlist::start->in(&s); 4837: if (lp) 4838: { fixlist *p; 4839: while ((p = *lp) != NULL) 4840: { 4841: //dbg_printf("Found reference at x%lx\n",p->Loffset); 4842: 4843: // Determine if it is a self-relative fixup we can 4844: // resolve directly. 4845: if (s->Sseg == p->Lseg && 4846: (s->Sclass == SCstatic || 4847: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 4848: (!(config.flags3 & CFG3pic) && s->Sclass == SCglobal)) && 4849: #else 4850: s->Sclass == SCglobal) && 4851: #endif 4852: s->Sxtrnnum == 0 && p->Lflags & CFselfrel) 4853: { targ_size_t ad; 4854: 4855: //printf("Soffset = x%lx, Loffset = x%lx, Lval = x%lx\n",s->Soffset,p->Loffset,p->Lval); 4856: ad = s->Soffset - p->Loffset - REGSIZE + p->Lval; 4857: obj_bytes(p->Lseg,p->Loffset,REGSIZE,&ad); 4858: } 4859: else 4860: { 4861: #if TARGET_OSX 4862: symbol *funcsymsave = funcsym_p; 4863: funcsym_p = p->Lfuncsym; 4864: reftoident(p->Lseg,p->Loffset,s,p->Lval,p->Lflags); 4865: funcsym_p = funcsymsave; 4866: #else 4867: reftoident(p->Lseg,p->Loffset,s,p->Lval,p->Lflags); 4868: #endif 4869: } 4870: *lp = p->Lnext; 4871: mem_free(p); /* remove from list */ 4872: } 4873: if (!fixlist::nodel) 4874: fixlist::start->del(&s); 4875: } 4876: } 4877: } 4878: 4879: /**************************** 4880: * End of module. Output remaining fixlist elements as references 4881: * to external symbols. 4882: */ 4883: 4884: STATIC int outfixlist_dg(void *parameter, void *pkey, void *pvalue) 4885: { 4886: //printf("outfixlist_dg(pkey = %p, pvalue = %p)\n", pkey, pvalue); 4887: symbol *s = *(symbol **)pkey; 4888: 4889: fixlist **plnext =