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,®,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, ®, 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, ®, 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, ®, 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 = (fixlist **)pvalue;
4890:
4891: while (*plnext)
4892: {
4893: fixlist *ln = *plnext;
4894:
4895: symbol_debug(s);
4896: //printf("outfixlist '%s' offset %04x\n",s->Sident,ln->Loffset);
4897:
4898: if (tybasic(s->ty()) == TYf16func)
4899: {
4900: obj_far16thunk(s); /* make it into a thunk */
4901: searchfixlist(s);
4902: }
4903: else
4904: {
4905: if (s->Sxtrnnum == 0)
4906: { if (s->Sclass == SCstatic)
4907: {
4908: #if SCPP
4909: if (s->Sdt)
4910: {
4911: outdata(s);
4912: searchfixlist(s);
4913: continue;
4914: }
4915:
4916: synerr(EM_no_static_def,prettyident(s)); // no definition found for static
4917: #else // MARS
4918: printf("Error: no definition for static %s\n",prettyident(s)); // no definition found for static
4919: err_exit(); // BUG: do better
4920: #endif
4921: }
4922: if (s->Sflags & SFLwasstatic)
4923: {
4924: // Put it in BSS
4925: s->Sclass = SCstatic;
4926: s->Sfl = FLunde;
4927: dtnzeros(&s->Sdt,type_size(s->Stype));
4928: outdata(s);
4929: searchfixlist(s);
4930: continue;
4931: }
4932: s->Sclass = SCextern; /* make it external */
4933: objextern(s);
4934: if (s->Sflags & SFLweak)
4935: {
4936: obj_wkext(s, NULL);
4937: }
4938: }
4939: #if TARGET_OSX
4940: symbol *funcsymsave = funcsym_p;
4941: funcsym_p = ln->Lfuncsym;
4942: reftoident(ln->Lseg,ln->Loffset,s,ln->Lval,ln->Lflags);
4943: funcsym_p = funcsymsave;
4944: #else
4945: reftoident(ln->Lseg,ln->Loffset,s,ln->Lval,ln->Lflags);
4946: #endif
4947: *plnext = ln->Lnext;
4948: #if TERMCODE
4949: mem_free(ln);
4950: #endif
4951: }
4952: }
4953: return 0;
4954: }
4955:
4956: void outfixlist()
4957: {
4958: //printf("outfixlist()\n");
4959: if (fixlist::start)
4960: {
4961: fixlist::nodel++;
4962: fixlist::start->apply(NULL, &outfixlist_dg);
4963: fixlist::nodel--;
4964: #if TERMCODE
4965: delete fixlist::start;
4966: fixlist::start = NULL;
4967: #endif
4968: }
4969: }
4970:
4971: /**********************************
4972: */
4973:
4974: #if HYDRATE
4975: void code_hydrate(code **pc)
4976: {
4977: code *c;
4978: unsigned char ins,rm;
4979: enum FL fl;
4980:
4981: assert(pc);
4982: while (*pc)
4983: {
4984: c = (code *) ph_hydrate(pc);
4985: if ((c->Iop & 0xFFFD00) == 0x0F3800)
4986: ins = inssize2[(c->Iop >> 8) & 0xFF];
4987: else if ((c->Iop & 0xFF00) == 0x0F00)
4988: ins = inssize2[c->Iop & 0xFF];
4989: else
4990: ins = inssize[c->Iop & 0xFF];
4991: switch (c->Iop)
4992: {
4993: default:
4994: break;
4995:
4996: case ESCAPE | ESClinnum:
4997: srcpos_hydrate(&c->IEV2.Vsrcpos);
4998: goto done;
4999:
5000: case ESCAPE | ESCctor:
5001: case ESCAPE | ESCdtor:
5002: el_hydrate(&c->IEV1.Vtor);
5003: goto done;
5004:
5005: case ASM:
5006: ph_hydrate(&c->IEV1.as.bytes);
5007: goto done;
5008: }
5009: if (!(ins & M) ||
5010: ((rm = c->Irm) & 0xC0) == 0xC0)
5011: goto do2; /* if no first operand */
5012: if (is32bitaddr(I32,c->Iflags))
5013: {
5014:
5015: if (
5016: ((rm & 0xC0) == 0 && !((rm & 7) == 4 && (c->Isib & 7) == 5 || (rm & 7) == 5))
5017: )
5018: goto do2; /* if no first operand */
5019: }
5020: else
5021: {
5022: if (
5023: ((rm & 0xC0) == 0 && !((rm & 7) == 6))
5024: )
5025: goto do2; /* if no first operand */
5026: }
5027: fl = (enum FL) c->IFL1;
5028: switch (fl)
5029: {
5030: case FLudata:
5031: case FLdata:
5032: case FLreg:
5033: case FLauto:
5034: case FLbprel:
5035: case FLpara:
5036: case FLcsdata:
5037: case FLfardata:
5038: case FLtlsdata:
5039: case FLfunc:
5040: case FLpseudo:
5041: case FLextern:
5042: case FLtmp:
5043: assert(flinsymtab[fl]);
5044: symbol_hydrate(&c->IEVsym1);
5045: symbol_debug(c->IEVsym1);
5046: break;
5047: case FLdatseg:
5048: case FLfltreg:
5049: case FLallocatmp:
5050: case FLcs:
5051: case FLndp:
5052: case FLoffset:
5053: case FLlocalsize:
5054: case FLconst:
5055: case FLframehandler:
5056: assert(!flinsymtab[fl]);
5057: break;
5058: case FLcode:
5059: (void) ph_hydrate(&c->IEV1.Vcode);
5060: break;
5061: case FLblock:
5062: case FLblockoff:
5063: (void) ph_hydrate(&c->IEV1.Vblock);
5064: break;
5065: #if SCPP
5066: case FLctor:
5067: case FLdtor:
5068: el_hydrate(&c->IEV1.Vtor);
5069: break;
5070: #endif
5071: case FLasm:
5072: (void) ph_hydrate(&c->IEV1.as.bytes);
5073: break;
5074: default:
5075: #ifdef DEBUG
5076: WRFL(fl);
5077: #endif
5078: assert(0);
5079: break;
5080: }
5081: do2:
5082: /* Ignore TEST (F6 and F7) opcodes */
5083: if (!(ins & T))
5084: goto done; /* if no second operand */
5085:
5086: fl = (enum FL) c->IFL2;
5087: switch (fl)
5088: {
5089: case FLudata:
5090: case FLdata:
5091: case FLreg:
5092: case FLauto:
5093: case FLbprel:
5094: case FLpara:
5095: case FLcsdata:
5096: case FLfardata:
5097: case FLtlsdata:
5098: case FLfunc:
5099: case FLpseudo:
5100: case FLextern:
5101: case FLtmp:
5102: assert(flinsymtab[fl]);
5103: symbol_hydrate(&c->IEVsym2);
5104: symbol_debug(c->IEVsym2);
5105: break;
5106: case FLdatseg:
5107: case FLfltreg:
5108: case FLallocatmp:
5109: case FLcs:
5110: case FLndp:
5111: case FLoffset:
5112: case FLlocalsize:
5113: case FLconst:
5114: case FLframehandler:
5115: assert(!flinsymtab[fl]);
5116: break;
5117: case FLcode:
5118: (void) ph_hydrate(&c->IEV2.Vcode);
5119: break;
5120: case FLblock:
5121: case FLblockoff:
5122: (void) ph_hydrate(&c->IEV2.Vblock);
5123: break;
5124: default:
5125: #ifdef DEBUG
5126: WRFL(fl);
5127: #endif
5128: assert(0);
5129: break;
5130: }
5131: done:
5132: ;
5133:
5134: pc = &code_next(c);
5135: }
5136: }
5137: #endif
5138:
5139: /**********************************
5140: */
5141:
5142: #if DEHYDRATE
5143: void code_dehydrate(code **pc)
5144: {
5145: code *c;
5146: unsigned char ins,rm;
5147: enum FL fl;
5148:
5149: while ((c = *pc) != NULL)
5150: {
5151: ph_dehydrate(pc);
5152:
5153: if ((c->Iop & 0xFFFD00) == 0x0F3800)
5154: ins = inssize2[(c->Iop >> 8) & 0xFF];
5155: else if ((c->Iop & 0xFF00) == 0x0F00)
5156: ins = inssize2[c->Iop & 0xFF];
5157: else
5158: ins = inssize[c->Iop & 0xFF];
5159: switch (c->Iop)
5160: {
5161: default:
5162: break;
5163:
5164: case ESCAPE | ESClinnum:
5165: srcpos_dehydrate(&c->IEV2.Vsrcpos);
5166: goto done;
5167:
5168: case ESCAPE | ESCctor:
5169: case ESCAPE | ESCdtor:
5170: el_dehydrate(&c->IEV1.Vtor);
5171: goto done;
5172:
5173: case ASM:
5174: ph_dehydrate(&c->IEV1.as.bytes);
5175: goto done;
5176: }
5177:
5178: if (!(ins & M) ||
5179: ((rm = c->Irm) & 0xC0) == 0xC0)
5180: goto do2; /* if no first operand */
5181: if (is32bitaddr(I32,c->Iflags))
5182: {
5183:
5184: if (
5185: ((rm & 0xC0) == 0 && !((rm & 7) == 4 && (c->Isib & 7) == 5 || (rm & 7) == 5))
5186: )
5187: goto do2; /* if no first operand */
5188: }
5189: else
5190: {
5191: if (
5192: ((rm & 0xC0) == 0 && !((rm & 7) == 6))
5193: )
5194: goto do2; /* if no first operand */
5195: }
5196: fl = (enum FL) c->IFL1;
5197: switch (fl)
5198: {
5199: case FLudata:
5200: case FLdata:
5201: case FLreg:
5202: case FLauto:
5203: case FLbprel:
5204: case FLpara:
5205: case FLcsdata:
5206: case FLfardata:
5207: case FLtlsdata:
5208: case FLfunc:
5209: case FLpseudo:
5210: case FLextern:
5211: case FLtmp:
5212: assert(flinsymtab[fl]);
5213: symbol_dehydrate(&c->IEVsym1);
5214: break;
5215: case FLdatseg:
5216: case FLfltreg:
5217: case FLallocatmp:
5218: case FLcs:
5219: case FLndp:
5220: case FLoffset:
5221: case FLlocalsize:
5222: case FLconst:
5223: case FLframehandler:
5224: assert(!flinsymtab[fl]);
5225: break;
5226: case FLcode:
5227: ph_dehydrate(&c->IEV1.Vcode);
5228: break;
5229: case FLblock:
5230: case FLblockoff:
5231: ph_dehydrate(&c->IEV1.Vblock);
5232: break;
5233: #if SCPP
5234: case FLctor:
5235: case FLdtor:
5236: el_dehydrate(&c->IEV1.Vtor);
5237: break;
5238: #endif
5239: case FLasm:
5240: ph_dehydrate(&c->IEV1.as.bytes);
5241: break;
5242: default:
5243: #ifdef DEBUG
5244: WRFL(fl);
5245: #endif
5246: assert(0);
5247: break;
5248: }
5249: do2:
5250: /* Ignore TEST (F6 and F7) opcodes */
5251: if (!(ins & T))
5252: goto done; /* if no second operand */
5253:
5254: fl = (enum FL) c->IFL2;
5255: switch (fl)
5256: {
5257: case FLudata:
5258: case FLdata:
5259: case FLreg:
5260: case FLauto:
5261: case FLbprel:
5262: case FLpara:
5263: case FLcsdata:
5264: case FLfardata:
5265: case FLtlsdata:
5266: case FLfunc:
5267: case FLpseudo:
5268: case FLextern:
5269: case FLtmp:
5270: assert(flinsymtab[fl]);
5271: symbol_dehydrate(&c->IEVsym2);
5272: break;
5273: case FLdatseg:
5274: case FLfltreg:
5275: case FLallocatmp:
5276: case FLcs:
5277: case FLndp:
5278: case FLoffset:
5279: case FLlocalsize:
5280: case FLconst:
5281: case FLframehandler:
5282: assert(!flinsymtab[fl]);
5283: break;
5284: case FLcode:
5285: ph_dehydrate(&c->IEV2.Vcode);
5286: break;
5287: case FLblock:
5288: case FLblockoff:
5289: ph_dehydrate(&c->IEV2.Vblock);
5290: break;
5291: default:
5292: #ifdef DEBUG
5293: WRFL(fl);
5294: #endif
5295: assert(0);
5296: break;
5297: }
5298: done:
5299: ;
5300: pc = &code_next(c);
5301: }
5302: }
5303: #endif
5304:
5305: /***************************
5306: * Debug code to dump code stucture.
5307: */
5308:
5309: #if DEBUG
5310:
5311: void WRcodlst(code *c)
5312: { for (; c; c = code_next(c))
5313: c->print();
5314: }
5315:
5316: void code::print()
5317: {
5318: unsigned char ins;
5319: code *c = this;
5320:
5321: if (c == CNIL)
5322: { printf("code 0\n");
5323: return;
5324: }
5325:
5326: unsigned op = c->Iop;
5327: if ((c->Iop & 0xFFFD00) == 0x0F3800)
5328: ins = inssize2[(op >> 8) & 0xFF];
5329: else if ((c->Iop & 0xFF00) == 0x0F00)
5330: ins = inssize2[op & 0xFF];
5331: else
5332: ins = inssize[op & 0xFF];
5333:
5334: printf("code %p: nxt=%p ",c,code_next(c));
5335: if (c->Irex)
5336: { printf("rex=%x ", c->Irex);
5337: if (c->Irex & REX_W)
5338: printf("W");
5339: if (c->Irex & REX_R)
5340: printf("R");
5341: if (c->Irex & REX_X)
5342: printf("X");
5343: if (c->Irex & REX_B)
5344: printf("B");
5345: printf(" ");
5346: }
5347: printf("op=%02x",op);
5348:
5349: if ((op & 0xFF) == ESCAPE)
5350: { if ((op & 0xFF00) == ESClinnum)
5351: { printf(" linnum = %d\n",c->IEV2.Vsrcpos.Slinnum);
5352: return;
5353: }
5354: printf(" ESCAPE %d",c->Iop >> 8);
5355: }
5356: if (c->Iflags)
5357: printf(" flg=%x",c->Iflags);
5358: if (ins & M)
5359: { unsigned rm = c->Irm;
5360: printf(" rm=%02x=%d,%d,%d",rm,(rm>>6)&3,(rm>>3)&7,rm&7);
5361: if (!I16 && issib(rm))
5362: { unsigned char sib = c->Isib;
5363: printf(" sib=%02x=%d,%d,%d",sib,(sib>>6)&3,(sib>>3)&7,sib&7);
5364: }
5365: if ((rm & 0xC7) == BPRM || (rm & 0xC0) == 0x80 || (rm & 0xC0) == 0x40)
5366: {
5367: switch (c->IFL1)
5368: {
5369: case FLconst:
5370: case FLoffset:
5371: printf(" int = %4d",c->IEV1.Vuns);
5372: break;
5373: case FLblock:
5374: printf(" block = %p",c->IEV1.Vblock);
5375: break;
5376: case FLswitch:
5377: case FLblockoff:
5378: case FLlocalsize:
5379: case FLframehandler:
5380: case 0:
5381: break;
5382: case FLdatseg:
5383: printf(" %d.%llx",c->IEVseg1,(unsigned long long)c->IEVpointer1);
5384: break;
5385: case FLauto:
5386: case FLreg:
5387: case FLdata:
5388: case FLudata:
5389: case FLpara:
5390: case FLtmp:
5391: case FLbprel:
5392: case FLtlsdata:
5393: printf(" sym='%s'",c->IEVsym1->Sident);
5394: break;
5395: case FLextern:
5396: printf(" FLextern offset = %4d",(int)c->IEVoffset1);
5397: break;
5398: default:
5399: WRFL((enum FL)c->IFL1);
5400: break;
5401: }
5402: }
5403: }
5404: if (ins & T)
5405: { printf(" "); WRFL((enum FL)c->IFL2);
5406: switch (c->IFL2)
5407: {
5408: case FLconst:
5409: printf(" int = %4d",c->IEV2.Vuns);
5410: break;
5411: case FLblock:
5412: printf(" block = %p",c->IEV2.Vblock);
5413: break;
5414: case FLswitch:
5415: case FLblockoff:
5416: case 0:
5417: case FLlocalsize:
5418: case FLframehandler:
5419: break;
5420: case FLdatseg:
5421: printf(" %d.%llx",c->IEVseg2,(unsigned long long)c->IEVpointer2);
5422: break;
5423: case FLauto:
5424: case FLreg:
5425: case FLpara:
5426: case FLtmp:
5427: case FLbprel:
5428: case FLfunc:
5429: case FLdata:
5430: case FLudata:
5431: case FLtlsdata:
5432: printf(" sym='%s'",c->IEVsym2->Sident);
5433: break;
5434: case FLcode:
5435: printf(" code = %p",c->IEV2.Vcode);
5436: break;
5437: default:
5438: WRFL((enum FL)c->IFL2);
5439: break;
5440: }
5441: }
5442: printf("\n");
5443: }
5444: #endif
5445:
5446: #endif // !SPP
5447: