Changeset 580
- Timestamp:
- 07/18/10 18:15:49 (14 years ago)
- Files:
-
- branches/dmd-1.x/src/backend/cod1.c (modified) (2 diffs)
- branches/dmd-1.x/src/backend/cod3.c (modified) (6 diffs)
- branches/dmd-1.x/src/backend/code.h (modified) (1 diff)
- branches/dmd-1.x/src/backend/el.c (modified) (2 diffs)
- trunk/src/backend/cod1.c (modified) (2 diffs)
- trunk/src/backend/cod3.c (modified) (6 diffs)
- trunk/src/backend/code.h (modified) (1 diff)
- trunk/src/backend/el.c (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/dmd-1.x/src/backend/cod1.c
r579 r580 542 542 * Can handle indirection operators, but not if they're common subs. 543 543 * Input: 544 544 * e -> elem where we get some of the data from 545 545 * cs -> partially filled code to add 546 546 * op = opcode 547 547 * reg = reg field of (mod reg r/m) 548 548 * offset = data to be added to Voffset field 549 549 * keepmsk = mask of registers we must not destroy 550 550 * desmsk = mask of registers destroyed by executing the instruction 551 551 * Returns: 552 552 * pointer to code generated 553 553 */ 554 554 555 555 code *loadea(elem *e,code *cs,unsigned op,unsigned reg,targ_size_t offset, 556 556 regm_t keepmsk,regm_t desmsk) 557 557 { 558 558 code *c,*cg,*cd; 559 559 560 560 #ifdef DEBUG 561 561 if (debugw) 562 printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%l d keepmsk=x%x desmsk=x%x\n",563 e,cs,op,reg, offset,keepmsk,desmsk);562 printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%lld keepmsk=x%x desmsk=x%x\n", 563 e,cs,op,reg,(unsigned long long)offset,keepmsk,desmsk); 564 564 #endif 565 565 566 566 assert(e); 567 567 cs->Iflags = 0; 568 568 cs->Irex = 0; 569 569 cs->Iop = op; 570 570 if (!I16 && op >= 0x100) // if 2 byte opcode 571 571 { cs->Iop = op >> 8; 572 572 cs->Iop2 = op; 573 573 } 574 574 tym_t tym = e->Ety; 575 575 int sz = tysize(tym); 576 576 577 577 /* Determine if location we want to get is in a register. If so, */ 578 578 /* substitute the register for the EA. */ 579 579 /* Note that operators don't go through this. CSE'd operators are */ 580 580 /* picked up by comsub(). */ 581 581 if (e->Ecount && /* if cse */ 582 582 e->Ecount != e->Ecomsub && /* and cse was generated */ 583 583 op != 0x8D && op != 0xC4 && /* and not an LEA or LES */ … … 1268 1268 { 1269 1269 pcs->Irm = modregrm(3,0,s->Spreg & 7); 1270 1270 if (s->Spreg & 8) 1271 1271 pcs->Irex |= REX_B; 1272 1272 regcon.used |= mask[s->Spreg]; 1273 1273 break; 1274 1274 } 1275 1275 } 1276 1276 else 1277 1277 regcon.params &= ~mask[s->Spreg]; 1278 1278 } 1279 1279 case FLtmp: 1280 1280 case FLbprel: 1281 1281 reflocal = TRUE; 1282 1282 pcs->Irm = modregrm(2,0,BPRM); 1283 1283 goto L2; 1284 1284 case FLextern: 1285 1285 if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0) 1286 1286 { 1287 1287 #if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1288 // Rewrite as GS:[0000] 1289 pcs->Irm = modregrm(0, 0, BPRM); 1290 pcs->IFL1 = FLconst; 1291 pcs->IEV1.Vuns = 0; 1292 pcs->Iflags = CFgs; 1288 // Rewrite as GS:[0000], or FS:[0000] for 64 bit 1289 if (I64) 1290 { 1291 pcs->Irm = modregrm(0, 0, 4); 1292 pcs->Isib = modregrm(0, 4, 5); // don't use [RIP] addressing 1293 pcs->IFL1 = FLconst; 1294 pcs->IEV1.Vuns = 0; 1295 pcs->Iflags = CFfs; 1296 } 1297 else 1298 { 1299 pcs->Irm = modregrm(0, 0, BPRM); 1300 pcs->IFL1 = FLconst; 1301 pcs->IEV1.Vuns = 0; 1302 pcs->Iflags = CFgs; 1303 } 1304 break; 1293 1305 #else 1294 1306 pcs->Iflags |= CFfs; // add FS: override 1295 1307 #endif 1296 1308 } 1297 1309 if (s->ty() & mTYcs && LARGECODE) 1298 1310 goto Lfardata; 1299 1311 goto L3; 1300 1312 case FLdata: 1301 1313 case FLudata: 1302 1314 case FLcsdata: 1303 1315 #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS 1304 1316 case FLgot: 1305 1317 case FLgotoff: 1306 1318 case FLtlsdata: 1307 1319 #endif 1308 1320 L3: 1309 1321 pcs->Irm = modregrm(0,0,BPRM); 1310 1322 L2: 1311 1323 if (fl == FLreg) 1312 1324 { assert(s->Sregm & regcon.mvar); branches/dmd-1.x/src/backend/cod3.c
r579 r580 49 49 static int EBPtoESP; // add to EBP offset to get ESP offset 50 50 static int AAoff; // offset of alloca temporary 51 51 52 52 #if ELFOBJ || MACHOBJ 53 53 #define JMPSEG CDATA 54 54 #define JMPOFF CDoffset 55 55 #else 56 56 #define JMPSEG DATA 57 57 #define JMPOFF Doffset 58 58 #endif 59 59 60 60 /************************ 61 61 * When we don't know whether a function symbol is defined or not 62 62 * within this module, we stuff it in this linked list of references 63 63 * to be fixed up later. 64 64 */ 65 65 66 66 struct fixlist 67 67 { symbol *Lsymbol; // symbol we don't know about 68 68 int Lseg; // where the fixup is going (CODE or DATA, never UDATA) 69 shortLflags; // CFxxxx69 int Lflags; // CFxxxx 70 70 targ_size_t Loffset; // addr of reference to symbol 71 71 targ_size_t Lval; // value to add into location 72 72 #if TARGET_OSX 73 73 symbol *Lfuncsym; // function the symbol goes in 74 74 #endif 75 75 fixlist *Lnext; // next in threaded list 76 76 77 77 static fixlist *start; 78 78 }; 79 79 80 80 fixlist *fixlist::start = NULL; 81 81 82 82 /************* 83 83 * Size in bytes of each instruction. 84 84 * 0 means illegal instruction. 85 85 * bit M: if there is a modregrm field (EV1 is reserved for modregrm) 86 86 * bit T: if there is a second operand (EV2) 87 87 * bit E: if second operand is only 8 bits 88 88 * bit A: a short version exists for the AX reg 89 89 * bit R: a short version exists for regs … … 3458 3458 unsigned char rm,mod,ins; 3459 3459 unsigned iflags; 3460 3460 unsigned i32 = I32 || I64; 3461 3461 unsigned a32 = i32; 3462 3462 3463 3463 #ifdef DEBUG 3464 3464 assert((a32 & ~1) == 0); 3465 3465 #endif 3466 3466 iflags = c->Iflags; 3467 3467 op = c->Iop; 3468 3468 switch (op) 3469 3469 { 3470 3470 case 0x0F: 3471 3471 ins = inssize2[c->Iop2]; 3472 3472 size = ins & 7; 3473 3473 break; 3474 3474 3475 3475 case NOP: 3476 3476 case ESCAPE: 3477 3477 size = 0; // since these won't be output 3478 goto Lret ;3478 goto Lret2; 3479 3479 3480 3480 case ASM: 3481 3481 if (c->Iflags == CFaddrsize) // kludge for DA inline asm 3482 3482 size = NPTRSIZE; 3483 3483 else 3484 3484 size = c->IEV1.as.len; 3485 goto Lret ;3485 goto Lret2; 3486 3486 3487 3487 case 0xA1: 3488 3488 case 0xA3: 3489 3489 if (c->Irex) 3490 3490 { 3491 3491 size = 9; // 64 bit immediate value for MOV to/from RAX 3492 3492 goto Lret; 3493 3493 } 3494 3494 goto Ldefault; 3495 3495 3496 3496 case 0xF6: /* TEST mem8,immed8 */ 3497 3497 ins = inssize[op]; 3498 3498 size = ins & 7; 3499 3499 if (i32) 3500 3500 size = inssize32[op]; 3501 3501 if ((c->Irm & (7<<3)) == 0) 3502 3502 size++; /* size of immed8 */ 3503 3503 break; 3504 3504 3505 3505 case 0xF7: … … 3582 3582 case 0x40: 3583 3583 size++; /* disp8 */ 3584 3584 break; 3585 3585 case 0x80: 3586 3586 size += 4; /* disp32 */ 3587 3587 break; 3588 3588 } 3589 3589 } 3590 3590 else 3591 3591 { // 16 bit addressing 3592 3592 if (mod == 0x40) /* 01: 8 bit displacement */ 3593 3593 size++; 3594 3594 else if (mod == 0x80 || (mod == 0 && (rm & 7) == 6)) 3595 3595 size += 2; 3596 3596 } 3597 3597 } 3598 3598 3599 3599 Lret: 3600 3600 if (c->Irex) 3601 3601 size++; 3602 Lret2: 3602 3603 //printf("op = x%02x, size = %d\n",op,size); 3603 3604 return size; 3604 3605 } 3605 3606 3606 3607 3607 3608 /******************************** 3608 3609 * Return !=0 if codes match. 3609 3610 */ 3610 3611 3611 3612 #if 0 3612 3613 3613 3614 int code_match(code *c1,code *c2) 3614 3615 { code cs1,cs2; 3615 3616 unsigned char ins; 3616 3617 3617 3618 if (c1 == c2) 3618 3619 goto match; 3619 3620 cs1 = *c1; 3620 3621 cs2 = *c2; 3621 3622 if (cs1.Iop != cs2.Iop) … … 3875 3875 { 3876 3876 rm = c->Irm; 3877 3877 GEN(rm); 3878 3878 3879 3879 // Look for an address size override when working with the 3880 3880 // MOD R/M and SIB bytes 3881 3881 3882 3882 if (is32bitaddr( I32, flags)) 3883 3883 { 3884 3884 if (issib(rm)) 3885 3885 GEN(c->Isib); 3886 3886 switch (rm & 0xC0) 3887 3887 { case 0x40: 3888 3888 do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 3889 3889 break; 3890 3890 case 0: 3891 3891 if (!(issib(rm) && (c->Isib & 7) == 5 || 3892 3892 (rm & 7) == 5)) 3893 3893 break; 3894 3894 case 0x80: 3895 do32bit((enum FL)c->IFL1,&c->IEV1,CFoff );3895 do32bit((enum FL)c->IFL1,&c->IEV1,CFoff | CFpc32); 3896 3896 break; 3897 3897 } 3898 3898 } 3899 3899 else 3900 3900 { 3901 3901 switch (rm & 0xC0) 3902 3902 { case 0x40: 3903 3903 do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 3904 3904 break; 3905 3905 case 0: 3906 3906 if ((rm & 7) != 6) 3907 3907 break; 3908 3908 case 0x80: 3909 3909 do16bit((enum FL)c->IFL1,&c->IEV1,CFoff); 3910 3910 break; 3911 3911 } 3912 3912 } 3913 3913 } 3914 3914 else 3915 3915 { … … 4128 4128 //printf("FLblockoff: offset = %x, Boffset = %x, funcoffset = %x\n", offset, uev->Vblock->Boffset, funcoffset); 4129 4129 reftocodseg(cseg,offset,uev->Vblock->Boffset); 4130 4130 break; 4131 4131 4132 4132 default: 4133 4133 #ifdef DEBUG 4134 4134 WRFL(fl); 4135 4135 #endif 4136 4136 assert(0); 4137 4137 } 4138 4138 offset += 8; 4139 4139 } 4140 4140 4141 4141 4142 4142 STATIC void do32bit(enum FL fl,union evc *uev,int flags) 4143 4143 { char *p; 4144 4144 symbol *s; 4145 4145 targ_size_t ad; 4146 4146 long tmp; 4147 4147 4148 //printf("do32bit(flags = x%x)\n", flags); 4148 4149 switch (fl) 4149 4150 { 4150 4151 case FLconst: 4151 4152 assert(sizeof(targ_size_t) == 4 || sizeof(targ_size_t) == 8); 4152 4153 ad = * (targ_size_t *) uev; 4153 4154 L1: 4154 4155 GENP(4,&ad); 4155 4156 return; 4156 4157 case FLdatseg: 4157 4158 FLUSH(); 4158 4159 reftodatseg(cseg,offset,uev->_EP.Vpointer,uev->_EP.Vseg,flags); 4159 4160 break; 4160 4161 #if 0 4161 4162 case FLcsdata: 4162 4163 FLUSH(); 4163 4164 reftocodseg(cseg,offset,uev->Vpointer); 4164 4165 break; 4165 4166 #endif 4166 4167 case FLframehandler: 4167 4168 framehandleroffset = OFFSET(); … … 4356 4357 void addtofixlist(symbol *s,targ_size_t soffset,int seg,targ_size_t val,int flags) 4357 4358 { fixlist *ln; 4358 4359 static char zeros[8]; 4359 4360 int numbytes; 4360 4361 4361 4362 //printf("addtofixlist(%p '%s')\n",s,s->Sident); 4362 4363 assert(flags); 4363 4364 ln = (fixlist *) mem_calloc(sizeof(fixlist)); 4364 4365 ln->Lsymbol = s; 4365 4366 ln->Loffset = soffset; 4366 4367 ln->Lseg = seg; 4367 4368 ln->Lflags = flags; 4368 4369 ln->Lval = val; 4369 4370 #if TARGET_OSX 4370 4371 ln->Lfuncsym = funcsym_p; 4371 4372 #endif 4372 4373 ln->Lnext = fixlist::start; 4373 4374 fixlist::start = ln; 4374 4375 #if TARGET_FLAT 4375 4376 numbytes = tysize[TYnptr]; 4377 if (I64 && !(flags & CFoffset64)) 4378 numbytes = 4; 4376 4379 assert(!(flags & CFseg)); 4377 4380 #else 4378 4381 switch (flags & (CFoff | CFseg)) 4379 4382 { 4380 4383 case CFoff: numbytes = tysize[TYnptr]; break; 4381 4384 case CFseg: numbytes = 2; break; 4382 4385 case CFoff | CFseg: numbytes = tysize[TYfptr]; break; 4383 4386 default: assert(0); 4384 4387 } 4385 4388 #endif 4386 4389 #ifdef DEBUG 4387 4390 assert(numbytes <= sizeof(zeros)); 4388 4391 #endif 4389 4392 obj_bytes(seg,soffset,numbytes,zeros); 4390 4393 } 4391 4394 4392 4395 /**************************** 4393 4396 * Given a function symbol we've just defined the offset for, 4394 4397 * search for it in the fixlist, and resolve any matches we find. 4395 4398 * Input: branches/dmd-1.x/src/backend/code.h
r577 r580 373 373 #define CFtarg 4 // this code is the target of a jump 374 374 #define CFseg 8 // get segment of immediate value 375 375 #define CFoff 0x10 // get offset of immediate value 376 376 #define CFss 0x20 // generate an SS: segment override (not with 377 377 // CFes at the same time, though!) 378 378 #define CFpsw 0x40 // we need the flags result after this instruction 379 379 #define CFopsize 0x80 // prefix with operand size 380 380 #define CFaddrsize 0x100 // prefix with address size 381 381 #define CFds 0x200 // need DS override (not with es, ss, or cs ) 382 382 #define CFcs 0x400 // need CS override 383 383 #define CFfs 0x800 // need FS override 384 384 #define CFgs (CFcs | CFfs) // need GS override 385 385 #define CFwait 0x1000 // If I32 it indicates when to output a WAIT 386 386 #define CFselfrel 0x2000 // if self-relative 387 387 #define CFunambig 0x4000 // indicates cannot be accessed by other addressing 388 388 // modes 389 389 #define CFtarg2 0x8000 // like CFtarg, but we can't optimize this away 390 390 #define CFvolatile 0x10000 // volatile reference, do not schedule 391 391 #define CFclassinit 0x20000 // class init code 392 392 #define CFoffset64 0x40000 // offset is 64 bits 393 #define CFpc32 0x80000 // I64: PC relative 32 bit fixup 393 394 394 395 #define CFPREFIX (CFSEG | CFopsize | CFaddrsize) 395 396 #define CFSEG (CFes | CFss | CFds | CFcs | CFfs | CFgs) 396 397 397 398 398 399 unsigned char Iop; 399 400 unsigned char Iop2; // second opcode byte 400 401 unsigned char Iop3; // third opcode byte 401 402 402 403 union 403 404 { unsigned _Iea; 404 405 struct 405 406 { 406 407 unsigned char _Irm; // reg/mode 407 408 unsigned char _Isib; // SIB byte 408 409 unsigned char _Irex; // REX prefix 409 410 } _ea; 410 411 } _EA; 411 412 412 413 #define Iea _EA._Iea branches/dmd-1.x/src/backend/el.c
r569 r580 1443 1443 #if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1444 1444 !(s->Stype->Tty & mTYthread) && 1445 1445 #endif 1446 1446 !tyfunc(s->ty())) 1447 1447 // Position Independent Code 1448 1448 return el_picvar(s); 1449 1449 #endif 1450 1450 symbol_debug(s); 1451 1451 type_debug(s->Stype); 1452 1452 e = el_calloc(); 1453 1453 e->Eoper = OPvar; 1454 1454 e->EV.sp.Vsym = s; 1455 1455 type_debug(s->Stype); 1456 1456 e->Ety = s->ty(); 1457 1457 if (s->Stype->Tty & mTYthread) 1458 1458 { 1459 1459 //printf("thread local %s\n", s->Sident); 1460 1460 #if TARGET_OSX 1461 1461 ; 1462 1462 #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1463 ; // add GS: override in back end1464 /* Generate:1465 * MOV reg,GS:[00000000] 1463 /* For 32 bit: 1464 * Generate for var locals: 1465 * MOV reg,GS:[00000000] // add GS: override in back end 1466 1466 * ADD reg, offset s@TLS_LE 1467 1467 * e => *(&s + *(GS:0)) 1468 * for locals, and for globals:1468 * For var globals: 1469 1469 * MOV reg,GS:[00000000] 1470 1470 * ADD reg, s@TLS_IE 1471 1471 * e => *(s + *(GS:0)) 1472 1472 * note different fixup 1473 ***************************************** 1474 * For 64 bit: 1475 * Generate for var locals: 1476 * MOV reg,FS:s@TPOFF32 1477 * For var globals: 1478 * MOV RAX,s@GOTTPOFF[RIP] 1479 * MOV reg,FS:[RAX] 1480 * 1481 * For address of locals: 1482 * MOV RAX,FS:[00] 1483 * LEA reg,s@TPOFF32[RAX] 1484 * e => &s + *(FS:0) 1485 * For address of globals: 1486 * MOV reg,FS:[00] 1487 * MOV RAX,s@GOTTPOFF[RIP] 1488 * ADD reg,RAX 1489 * e => s + *(FS:0) 1490 * This leaves us with a problem, as the 'var' version cannot simply have 1491 * its address taken, as what is the address of FS:s ? The (not so efficient) 1492 * solution is to just use the second address form, and * it. 1493 * Turns out that is identical to the 32 bit version, except GS => FS and the 1494 * fixups are different. 1495 * In the future, we should figure out a way to optimize to the 'var' version. 1473 1496 */ 1474 elem *e1,*e2; 1475 1476 e1 = el_calloc(); 1497 elem *e1 = el_calloc(); 1477 1498 e1->EV.sp.Vsym = s; 1478 1499 if (s->Sclass == SCstatic || s->Sclass == SClocstat) 1479 1500 { e1->Eoper = OPrelconst; 1480 1501 e1->Ety = TYnptr; 1481 1502 } 1482 1503 else 1483 1504 { 1484 1505 e1->Eoper = OPvar; 1485 1506 e1->Ety = TYnptr; 1486 1507 } 1487 1508 1488 // We'll fix this up in the back end to be GS:[0000] 1489 e2 = el_calloc(); 1509 /* Fake GS:[0000] as a load of _tls_array, and then in the back end recognize 1510 * the fake and rewrite it as GS:[0000] (or FS:[0000] for I64), because there is 1511 * no way to represent segment overrides in the elem nodes. 1512 */ 1513 elem *e2 = el_calloc(); 1490 1514 e2->Eoper = OPvar; 1491 1515 e2->EV.sp.Vsym = rtlsym[RTLSYM_TLS_ARRAY]; 1492 1516 e2->Ety = e2->EV.sp.Vsym->ty(); 1493 1517 1494 1518 e->Eoper = OPind; 1495 1519 e->E1 = el_bin(OPadd,e1->Ety,e2,e1); 1496 1520 e->E2 = NULL; 1497 1521 #else 1498 1522 /* 1499 1523 mov EAX,FS:__tls_array 1500 1524 mov ECX,__tls_index 1501 1525 mov EAX,[ECX*4][EAX] 1502 1526 inc dword ptr _t[EAX] 1503 1527 1504 1528 e => *(&s + *(FS:_tls_array + _tls_index * 4)) 1505 1529 1506 1530 If this is an executable app, not a dll, _tls_index 1507 1531 can be assumed to be 0. 1508 1532 */ 1509 1533 elem *e1,*e2,*ea; … … 3070 3094 { 3071 3095 if (e->E2) 3072 3096 dbg_printf("%p %p\n",e->E1,e->E2); 3073 3097 else 3074 3098 dbg_printf("%p\n",e->E1); 3075 3099 elem_print(e->E1); 3076 3100 } 3077 3101 else if (OTbinary(e->Eoper)) 3078 3102 { 3079 3103 if (!PARSER && e->Eoper == OPstreq) 3080 3104 dbg_printf("bytes=%d ",e->Enumbytes); 3081 3105 dbg_printf("%p %p\n",e->E1,e->E2); 3082 3106 elem_print(e->E1); 3083 3107 elem_print(e->E2); 3084 3108 } 3085 3109 else 3086 3110 { 3087 3111 switch (e->Eoper) 3088 3112 { 3089 3113 case OPrelconst: 3090 dbg_printf(" %l d+&",e->Eoffset);3114 dbg_printf(" %lld+&",(unsigned long long)e->Eoffset); 3091 3115 dbg_printf(" %s",e->EV.sp.Vsym->Sident); 3092 3116 break; 3093 3117 case OPvar: 3094 3118 if (e->Eoffset) 3095 dbg_printf(" %l d+",e->Eoffset);3119 dbg_printf(" %lld+",(unsigned long long)e->Eoffset); 3096 3120 dbg_printf(" %s",e->EV.sp.Vsym->Sident); 3097 3121 break; 3098 3122 case OPasm: 3099 3123 case OPstring: 3100 3124 case OPhstring: 3101 dbg_printf(" '%s',%l d\n",e->EV.ss.Vstring,e->EV.ss.Voffset);3125 dbg_printf(" '%s',%lld\n",e->EV.ss.Vstring,(unsigned long long)e->EV.ss.Voffset); 3102 3126 break; 3103 3127 case OPconst: 3104 3128 tym = tybasic(typemask(e)); 3105 3129 case_tym: 3106 3130 switch (tym) 3107 3131 { case TYbool: 3108 3132 case TYchar: 3109 3133 case TYschar: 3110 3134 case TYuchar: 3111 3135 dbg_printf("%d ",e->EV.Vuchar); 3112 3136 break; 3113 3137 #if TX86 3114 3138 case TYsptr: 3115 3139 #if JHANDLE 3116 3140 case TYjhandle: 3117 3141 #endif 3118 3142 case TYnullptr: 3119 3143 case TYnptr: 3120 3144 case TYcptr: 3121 3145 #endif trunk/src/backend/cod1.c
r579 r580 542 542 * Can handle indirection operators, but not if they're common subs. 543 543 * Input: 544 544 * e -> elem where we get some of the data from 545 545 * cs -> partially filled code to add 546 546 * op = opcode 547 547 * reg = reg field of (mod reg r/m) 548 548 * offset = data to be added to Voffset field 549 549 * keepmsk = mask of registers we must not destroy 550 550 * desmsk = mask of registers destroyed by executing the instruction 551 551 * Returns: 552 552 * pointer to code generated 553 553 */ 554 554 555 555 code *loadea(elem *e,code *cs,unsigned op,unsigned reg,targ_size_t offset, 556 556 regm_t keepmsk,regm_t desmsk) 557 557 { 558 558 code *c,*cg,*cd; 559 559 560 560 #ifdef DEBUG 561 561 if (debugw) 562 printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%l d keepmsk=x%x desmsk=x%x\n",563 e,cs,op,reg, offset,keepmsk,desmsk);562 printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%lld keepmsk=x%x desmsk=x%x\n", 563 e,cs,op,reg,(unsigned long long)offset,keepmsk,desmsk); 564 564 #endif 565 565 566 566 assert(e); 567 567 cs->Iflags = 0; 568 568 cs->Irex = 0; 569 569 cs->Iop = op; 570 570 if (!I16 && op >= 0x100) // if 2 byte opcode 571 571 { cs->Iop = op >> 8; 572 572 cs->Iop2 = op; 573 573 } 574 574 tym_t tym = e->Ety; 575 575 int sz = tysize(tym); 576 576 577 577 /* Determine if location we want to get is in a register. If so, */ 578 578 /* substitute the register for the EA. */ 579 579 /* Note that operators don't go through this. CSE'd operators are */ 580 580 /* picked up by comsub(). */ 581 581 if (e->Ecount && /* if cse */ 582 582 e->Ecount != e->Ecomsub && /* and cse was generated */ 583 583 op != 0x8D && op != 0xC4 && /* and not an LEA or LES */ … … 1268 1268 { 1269 1269 pcs->Irm = modregrm(3,0,s->Spreg & 7); 1270 1270 if (s->Spreg & 8) 1271 1271 pcs->Irex |= REX_B; 1272 1272 regcon.used |= mask[s->Spreg]; 1273 1273 break; 1274 1274 } 1275 1275 } 1276 1276 else 1277 1277 regcon.params &= ~mask[s->Spreg]; 1278 1278 } 1279 1279 case FLtmp: 1280 1280 case FLbprel: 1281 1281 reflocal = TRUE; 1282 1282 pcs->Irm = modregrm(2,0,BPRM); 1283 1283 goto L2; 1284 1284 case FLextern: 1285 1285 if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0) 1286 1286 { 1287 1287 #if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1288 // Rewrite as GS:[0000] 1289 pcs->Irm = modregrm(0, 0, BPRM); 1290 pcs->IFL1 = FLconst; 1291 pcs->IEV1.Vuns = 0; 1292 pcs->Iflags = CFgs; 1288 // Rewrite as GS:[0000], or FS:[0000] for 64 bit 1289 if (I64) 1290 { 1291 pcs->Irm = modregrm(0, 0, 4); 1292 pcs->Isib = modregrm(0, 4, 5); // don't use [RIP] addressing 1293 pcs->IFL1 = FLconst; 1294 pcs->IEV1.Vuns = 0; 1295 pcs->Iflags = CFfs; 1296 } 1297 else 1298 { 1299 pcs->Irm = modregrm(0, 0, BPRM); 1300 pcs->IFL1 = FLconst; 1301 pcs->IEV1.Vuns = 0; 1302 pcs->Iflags = CFgs; 1303 } 1304 break; 1293 1305 #else 1294 1306 pcs->Iflags |= CFfs; // add FS: override 1295 1307 #endif 1296 1308 } 1297 1309 if (s->ty() & mTYcs && LARGECODE) 1298 1310 goto Lfardata; 1299 1311 goto L3; 1300 1312 case FLdata: 1301 1313 case FLudata: 1302 1314 case FLcsdata: 1303 1315 #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS 1304 1316 case FLgot: 1305 1317 case FLgotoff: 1306 1318 case FLtlsdata: 1307 1319 #endif 1308 1320 L3: 1309 1321 pcs->Irm = modregrm(0,0,BPRM); 1310 1322 L2: 1311 1323 if (fl == FLreg) 1312 1324 { assert(s->Sregm & regcon.mvar); trunk/src/backend/cod3.c
r579 r580 49 49 static int EBPtoESP; // add to EBP offset to get ESP offset 50 50 static int AAoff; // offset of alloca temporary 51 51 52 52 #if ELFOBJ || MACHOBJ 53 53 #define JMPSEG CDATA 54 54 #define JMPOFF CDoffset 55 55 #else 56 56 #define JMPSEG DATA 57 57 #define JMPOFF Doffset 58 58 #endif 59 59 60 60 /************************ 61 61 * When we don't know whether a function symbol is defined or not 62 62 * within this module, we stuff it in this linked list of references 63 63 * to be fixed up later. 64 64 */ 65 65 66 66 struct fixlist 67 67 { symbol *Lsymbol; // symbol we don't know about 68 68 int Lseg; // where the fixup is going (CODE or DATA, never UDATA) 69 shortLflags; // CFxxxx69 int Lflags; // CFxxxx 70 70 targ_size_t Loffset; // addr of reference to symbol 71 71 targ_size_t Lval; // value to add into location 72 72 #if TARGET_OSX 73 73 symbol *Lfuncsym; // function the symbol goes in 74 74 #endif 75 75 fixlist *Lnext; // next in threaded list 76 76 77 77 static fixlist *start; 78 78 }; 79 79 80 80 fixlist *fixlist::start = NULL; 81 81 82 82 /************* 83 83 * Size in bytes of each instruction. 84 84 * 0 means illegal instruction. 85 85 * bit M: if there is a modregrm field (EV1 is reserved for modregrm) 86 86 * bit T: if there is a second operand (EV2) 87 87 * bit E: if second operand is only 8 bits 88 88 * bit A: a short version exists for the AX reg 89 89 * bit R: a short version exists for regs … … 3458 3458 unsigned char rm,mod,ins; 3459 3459 unsigned iflags; 3460 3460 unsigned i32 = I32 || I64; 3461 3461 unsigned a32 = i32; 3462 3462 3463 3463 #ifdef DEBUG 3464 3464 assert((a32 & ~1) == 0); 3465 3465 #endif 3466 3466 iflags = c->Iflags; 3467 3467 op = c->Iop; 3468 3468 switch (op) 3469 3469 { 3470 3470 case 0x0F: 3471 3471 ins = inssize2[c->Iop2]; 3472 3472 size = ins & 7; 3473 3473 break; 3474 3474 3475 3475 case NOP: 3476 3476 case ESCAPE: 3477 3477 size = 0; // since these won't be output 3478 goto Lret ;3478 goto Lret2; 3479 3479 3480 3480 case ASM: 3481 3481 if (c->Iflags == CFaddrsize) // kludge for DA inline asm 3482 3482 size = NPTRSIZE; 3483 3483 else 3484 3484 size = c->IEV1.as.len; 3485 goto Lret ;3485 goto Lret2; 3486 3486 3487 3487 case 0xA1: 3488 3488 case 0xA3: 3489 3489 if (c->Irex) 3490 3490 { 3491 3491 size = 9; // 64 bit immediate value for MOV to/from RAX 3492 3492 goto Lret; 3493 3493 } 3494 3494 goto Ldefault; 3495 3495 3496 3496 case 0xF6: /* TEST mem8,immed8 */ 3497 3497 ins = inssize[op]; 3498 3498 size = ins & 7; 3499 3499 if (i32) 3500 3500 size = inssize32[op]; 3501 3501 if ((c->Irm & (7<<3)) == 0) 3502 3502 size++; /* size of immed8 */ 3503 3503 break; 3504 3504 3505 3505 case 0xF7: … … 3582 3582 case 0x40: 3583 3583 size++; /* disp8 */ 3584 3584 break; 3585 3585 case 0x80: 3586 3586 size += 4; /* disp32 */ 3587 3587 break; 3588 3588 } 3589 3589 } 3590 3590 else 3591 3591 { // 16 bit addressing 3592 3592 if (mod == 0x40) /* 01: 8 bit displacement */ 3593 3593 size++; 3594 3594 else if (mod == 0x80 || (mod == 0 && (rm & 7) == 6)) 3595 3595 size += 2; 3596 3596 } 3597 3597 } 3598 3598 3599 3599 Lret: 3600 3600 if (c->Irex) 3601 3601 size++; 3602 Lret2: 3602 3603 //printf("op = x%02x, size = %d\n",op,size); 3603 3604 return size; 3604 3605 } 3605 3606 3606 3607 3607 3608 /******************************** 3608 3609 * Return !=0 if codes match. 3609 3610 */ 3610 3611 3611 3612 #if 0 3612 3613 3613 3614 int code_match(code *c1,code *c2) 3614 3615 { code cs1,cs2; 3615 3616 unsigned char ins; 3616 3617 3617 3618 if (c1 == c2) 3618 3619 goto match; 3619 3620 cs1 = *c1; 3620 3621 cs2 = *c2; 3621 3622 if (cs1.Iop != cs2.Iop) … … 3875 3875 { 3876 3876 rm = c->Irm; 3877 3877 GEN(rm); 3878 3878 3879 3879 // Look for an address size override when working with the 3880 3880 // MOD R/M and SIB bytes 3881 3881 3882 3882 if (is32bitaddr( I32, flags)) 3883 3883 { 3884 3884 if (issib(rm)) 3885 3885 GEN(c->Isib); 3886 3886 switch (rm & 0xC0) 3887 3887 { case 0x40: 3888 3888 do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 3889 3889 break; 3890 3890 case 0: 3891 3891 if (!(issib(rm) && (c->Isib & 7) == 5 || 3892 3892 (rm & 7) == 5)) 3893 3893 break; 3894 3894 case 0x80: 3895 do32bit((enum FL)c->IFL1,&c->IEV1,CFoff );3895 do32bit((enum FL)c->IFL1,&c->IEV1,CFoff | CFpc32); 3896 3896 break; 3897 3897 } 3898 3898 } 3899 3899 else 3900 3900 { 3901 3901 switch (rm & 0xC0) 3902 3902 { case 0x40: 3903 3903 do8bit((enum FL) c->IFL1,&c->IEV1); // 8 bit 3904 3904 break; 3905 3905 case 0: 3906 3906 if ((rm & 7) != 6) 3907 3907 break; 3908 3908 case 0x80: 3909 3909 do16bit((enum FL)c->IFL1,&c->IEV1,CFoff); 3910 3910 break; 3911 3911 } 3912 3912 } 3913 3913 } 3914 3914 else 3915 3915 { … … 4128 4128 //printf("FLblockoff: offset = %x, Boffset = %x, funcoffset = %x\n", offset, uev->Vblock->Boffset, funcoffset); 4129 4129 reftocodseg(cseg,offset,uev->Vblock->Boffset); 4130 4130 break; 4131 4131 4132 4132 default: 4133 4133 #ifdef DEBUG 4134 4134 WRFL(fl); 4135 4135 #endif 4136 4136 assert(0); 4137 4137 } 4138 4138 offset += 8; 4139 4139 } 4140 4140 4141 4141 4142 4142 STATIC void do32bit(enum FL fl,union evc *uev,int flags) 4143 4143 { char *p; 4144 4144 symbol *s; 4145 4145 targ_size_t ad; 4146 4146 long tmp; 4147 4147 4148 //printf("do32bit(flags = x%x)\n", flags); 4148 4149 switch (fl) 4149 4150 { 4150 4151 case FLconst: 4151 4152 assert(sizeof(targ_size_t) == 4 || sizeof(targ_size_t) == 8); 4152 4153 ad = * (targ_size_t *) uev; 4153 4154 L1: 4154 4155 GENP(4,&ad); 4155 4156 return; 4156 4157 case FLdatseg: 4157 4158 FLUSH(); 4158 4159 reftodatseg(cseg,offset,uev->_EP.Vpointer,uev->_EP.Vseg,flags); 4159 4160 break; 4160 4161 #if 0 4161 4162 case FLcsdata: 4162 4163 FLUSH(); 4163 4164 reftocodseg(cseg,offset,uev->Vpointer); 4164 4165 break; 4165 4166 #endif 4166 4167 case FLframehandler: 4167 4168 framehandleroffset = OFFSET(); … … 4356 4357 void addtofixlist(symbol *s,targ_size_t soffset,int seg,targ_size_t val,int flags) 4357 4358 { fixlist *ln; 4358 4359 static char zeros[8]; 4359 4360 int numbytes; 4360 4361 4361 4362 //printf("addtofixlist(%p '%s')\n",s,s->Sident); 4362 4363 assert(flags); 4363 4364 ln = (fixlist *) mem_calloc(sizeof(fixlist)); 4364 4365 ln->Lsymbol = s; 4365 4366 ln->Loffset = soffset; 4366 4367 ln->Lseg = seg; 4367 4368 ln->Lflags = flags; 4368 4369 ln->Lval = val; 4369 4370 #if TARGET_OSX 4370 4371 ln->Lfuncsym = funcsym_p; 4371 4372 #endif 4372 4373 ln->Lnext = fixlist::start; 4373 4374 fixlist::start = ln; 4374 4375 #if TARGET_FLAT 4375 4376 numbytes = tysize[TYnptr]; 4377 if (I64 && !(flags & CFoffset64)) 4378 numbytes = 4; 4376 4379 assert(!(flags & CFseg)); 4377 4380 #else 4378 4381 switch (flags & (CFoff | CFseg)) 4379 4382 { 4380 4383 case CFoff: numbytes = tysize[TYnptr]; break; 4381 4384 case CFseg: numbytes = 2; break; 4382 4385 case CFoff | CFseg: numbytes = tysize[TYfptr]; break; 4383 4386 default: assert(0); 4384 4387 } 4385 4388 #endif 4386 4389 #ifdef DEBUG 4387 4390 assert(numbytes <= sizeof(zeros)); 4388 4391 #endif 4389 4392 obj_bytes(seg,soffset,numbytes,zeros); 4390 4393 } 4391 4394 4392 4395 /**************************** 4393 4396 * Given a function symbol we've just defined the offset for, 4394 4397 * search for it in the fixlist, and resolve any matches we find. 4395 4398 * Input: trunk/src/backend/code.h
r577 r580 373 373 #define CFtarg 4 // this code is the target of a jump 374 374 #define CFseg 8 // get segment of immediate value 375 375 #define CFoff 0x10 // get offset of immediate value 376 376 #define CFss 0x20 // generate an SS: segment override (not with 377 377 // CFes at the same time, though!) 378 378 #define CFpsw 0x40 // we need the flags result after this instruction 379 379 #define CFopsize 0x80 // prefix with operand size 380 380 #define CFaddrsize 0x100 // prefix with address size 381 381 #define CFds 0x200 // need DS override (not with es, ss, or cs ) 382 382 #define CFcs 0x400 // need CS override 383 383 #define CFfs 0x800 // need FS override 384 384 #define CFgs (CFcs | CFfs) // need GS override 385 385 #define CFwait 0x1000 // If I32 it indicates when to output a WAIT 386 386 #define CFselfrel 0x2000 // if self-relative 387 387 #define CFunambig 0x4000 // indicates cannot be accessed by other addressing 388 388 // modes 389 389 #define CFtarg2 0x8000 // like CFtarg, but we can't optimize this away 390 390 #define CFvolatile 0x10000 // volatile reference, do not schedule 391 391 #define CFclassinit 0x20000 // class init code 392 392 #define CFoffset64 0x40000 // offset is 64 bits 393 #define CFpc32 0x80000 // I64: PC relative 32 bit fixup 393 394 394 395 #define CFPREFIX (CFSEG | CFopsize | CFaddrsize) 395 396 #define CFSEG (CFes | CFss | CFds | CFcs | CFfs | CFgs) 396 397 397 398 398 399 unsigned char Iop; 399 400 unsigned char Iop2; // second opcode byte 400 401 unsigned char Iop3; // third opcode byte 401 402 402 403 union 403 404 { unsigned _Iea; 404 405 struct 405 406 { 406 407 unsigned char _Irm; // reg/mode 407 408 unsigned char _Isib; // SIB byte 408 409 unsigned char _Irex; // REX prefix 409 410 } _ea; 410 411 } _EA; 411 412 412 413 #define Iea _EA._Iea trunk/src/backend/el.c
r569 r580 1443 1443 #if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1444 1444 !(s->Stype->Tty & mTYthread) && 1445 1445 #endif 1446 1446 !tyfunc(s->ty())) 1447 1447 // Position Independent Code 1448 1448 return el_picvar(s); 1449 1449 #endif 1450 1450 symbol_debug(s); 1451 1451 type_debug(s->Stype); 1452 1452 e = el_calloc(); 1453 1453 e->Eoper = OPvar; 1454 1454 e->EV.sp.Vsym = s; 1455 1455 type_debug(s->Stype); 1456 1456 e->Ety = s->ty(); 1457 1457 if (s->Stype->Tty & mTYthread) 1458 1458 { 1459 1459 //printf("thread local %s\n", s->Sident); 1460 1460 #if TARGET_OSX 1461 1461 ; 1462 1462 #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS 1463 ; // add GS: override in back end1464 /* Generate:1465 * MOV reg,GS:[00000000] 1463 /* For 32 bit: 1464 * Generate for var locals: 1465 * MOV reg,GS:[00000000] // add GS: override in back end 1466 1466 * ADD reg, offset s@TLS_LE 1467 1467 * e => *(&s + *(GS:0)) 1468 * for locals, and for globals:1468 * For var globals: 1469 1469 * MOV reg,GS:[00000000] 1470 1470 * ADD reg, s@TLS_IE 1471 1471 * e => *(s + *(GS:0)) 1472 1472 * note different fixup 1473 ***************************************** 1474 * For 64 bit: 1475 * Generate for var locals: 1476 * MOV reg,FS:s@TPOFF32 1477 * For var globals: 1478 * MOV RAX,s@GOTTPOFF[RIP] 1479 * MOV reg,FS:[RAX] 1480 * 1481 * For address of locals: 1482 * MOV RAX,FS:[00] 1483 * LEA reg,s@TPOFF32[RAX] 1484 * e => &s + *(FS:0) 1485 * For address of globals: 1486 * MOV reg,FS:[00] 1487 * MOV RAX,s@GOTTPOFF[RIP] 1488 * ADD reg,RAX 1489 * e => s + *(FS:0) 1490 * This leaves us with a problem, as the 'var' version cannot simply have 1491 * its address taken, as what is the address of FS:s ? The (not so efficient) 1492 * solution is to just use the second address form, and * it. 1493 * Turns out that is identical to the 32 bit version, except GS => FS and the 1494 * fixups are different. 1495 * In the future, we should figure out a way to optimize to the 'var' version. 1473 1496 */ 1474 elem *e1,*e2; 1475 1476 e1 = el_calloc(); 1497 elem *e1 = el_calloc(); 1477 1498 e1->EV.sp.Vsym = s; 1478 1499 if (s->Sclass == SCstatic || s->Sclass == SClocstat) 1479 1500 { e1->Eoper = OPrelconst; 1480 1501 e1->Ety = TYnptr; 1481 1502 } 1482 1503 else 1483 1504 { 1484 1505 e1->Eoper = OPvar; 1485 1506 e1->Ety = TYnptr; 1486 1507 } 1487 1508 1488 // We'll fix this up in the back end to be GS:[0000] 1489 e2 = el_calloc(); 1509 /* Fake GS:[0000] as a load of _tls_array, and then in the back end recognize 1510 * the fake and rewrite it as GS:[0000] (or FS:[0000] for I64), because there is 1511 * no way to represent segment overrides in the elem nodes. 1512 */ 1513 elem *e2 = el_calloc(); 1490 1514 e2->Eoper = OPvar; 1491 1515 e2->EV.sp.Vsym = rtlsym[RTLSYM_TLS_ARRAY]; 1492 1516 e2->Ety = e2->EV.sp.Vsym->ty(); 1493 1517 1494 1518 e->Eoper = OPind; 1495 1519 e->E1 = el_bin(OPadd,e1->Ety,e2,e1); 1496 1520 e->E2 = NULL; 1497 1521 #else 1498 1522 /* 1499 1523 mov EAX,FS:__tls_array 1500 1524 mov ECX,__tls_index 1501 1525 mov EAX,[ECX*4][EAX] 1502 1526 inc dword ptr _t[EAX] 1503 1527 1504 1528 e => *(&s + *(FS:_tls_array + _tls_index * 4)) 1505 1529 1506 1530 If this is an executable app, not a dll, _tls_index 1507 1531 can be assumed to be 0. 1508 1532 */ 1509 1533 elem *e1,*e2,*ea; … … 3070 3094 { 3071 3095 if (e->E2) 3072 3096 dbg_printf("%p %p\n",e->E1,e->E2); 3073 3097 else 3074 3098 dbg_printf("%p\n",e->E1); 3075 3099 elem_print(e->E1); 3076 3100 } 3077 3101 else if (OTbinary(e->Eoper)) 3078 3102 { 3079 3103 if (!PARSER && e->Eoper == OPstreq) 3080 3104 dbg_printf("bytes=%d ",e->Enumbytes); 3081 3105 dbg_printf("%p %p\n",e->E1,e->E2); 3082 3106 elem_print(e->E1); 3083 3107 elem_print(e->E2); 3084 3108 } 3085 3109 else 3086 3110 { 3087 3111 switch (e->Eoper) 3088 3112 { 3089 3113 case OPrelconst: 3090 dbg_printf(" %l d+&",e->Eoffset);3114 dbg_printf(" %lld+&",(unsigned long long)e->Eoffset); 3091 3115 dbg_printf(" %s",e->EV.sp.Vsym->Sident); 3092 3116 break; 3093 3117 case OPvar: 3094 3118 if (e->Eoffset) 3095 dbg_printf(" %l d+",e->Eoffset);3119 dbg_printf(" %lld+",(unsigned long long)e->Eoffset); 3096 3120 dbg_printf(" %s",e->EV.sp.Vsym->Sident); 3097 3121 break; 3098 3122 case OPasm: 3099 3123 case OPstring: 3100 3124 case OPhstring: 3101 dbg_printf(" '%s',%l d\n",e->EV.ss.Vstring,e->EV.ss.Voffset);3125 dbg_printf(" '%s',%lld\n",e->EV.ss.Vstring,(unsigned long long)e->EV.ss.Voffset); 3102 3126 break; 3103 3127 case OPconst: 3104 3128 tym = tybasic(typemask(e)); 3105 3129 case_tym: 3106 3130 switch (tym) 3107 3131 { case TYbool: 3108 3132 case TYchar: 3109 3133 case TYschar: 3110 3134 case TYuchar: 3111 3135 dbg_printf("%d ",e->EV.Vuchar); 3112 3136 break; 3113 3137 #if TX86 3114 3138 case TYsptr: 3115 3139 #if JHANDLE 3116 3140 case TYjhandle: 3117 3141 #endif 3118 3142 case TYnullptr: 3119 3143 case TYnptr: 3120 3144 case TYcptr: 3121 3145 #endif
