1 /** 2 * Generate elems for fixed, PIC, and PIE code generation. 3 * 4 * Compiler implementation of the 5 * $(LINK2 http://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 1985-1998 by Symantec 8 * Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/elpicpie.d, backend/elpicpie.d) 12 */ 13 14 module dmd.backend.elpicpie; 15 16 version (SCPP) 17 { 18 version = COMPILE; 19 version = SCPP_HTOD; 20 } 21 version (HTOD) 22 { 23 version = COMPILE; 24 version = SCPP_HTOD; 25 } 26 version (MARS) 27 { 28 version = COMPILE; 29 } 30 31 version (COMPILE) 32 { 33 34 import core.stdc.stdarg; 35 import core.stdc.stdio; 36 import core.stdc.stdlib; 37 import core.stdc.string; 38 39 import dmd.backend.cdef; 40 import dmd.backend.cc; 41 import dmd.backend.code; 42 import dmd.backend.code_x86; 43 import dmd.backend.el; 44 import dmd.backend.global; 45 import dmd.backend.obj; 46 import dmd.backend.oper; 47 import dmd.backend.rtlsym; 48 import dmd.backend.ty; 49 import dmd.backend.type; 50 51 version (SCPP_HTOD) 52 { 53 import msgs2; 54 } 55 56 extern (C++): 57 58 nothrow: 59 60 /************************** 61 * Make an elem out of a symbol. 62 */ 63 64 version (MARS) 65 { 66 elem * el_var(Symbol *s) 67 { 68 elem *e; 69 //printf("el_var(s = '%s')\n", s.Sident); 70 //printf("%x\n", s.Stype.Tty); 71 if (config.exe & EX_posix) 72 { 73 if (config.flags3 & CFG3pie && 74 s.Stype.Tty & mTYthread) 75 return el_pievar(s); // Position Independent Executable 76 77 if (config.flags3 & CFG3pic && 78 !tyfunc(s.ty())) 79 return el_picvar(s); // Position Independent Code 80 } 81 82 if (config.exe & (EX_OSX | EX_OSX64)) 83 { 84 } 85 else if (config.exe & EX_posix) 86 { 87 if (config.flags3 & CFG3pic && tyfunc(s.ty())) 88 { 89 switch (s.Sclass) 90 { 91 case SCcomdat: 92 case SCcomdef: 93 case SCglobal: 94 case SCextern: 95 el_alloc_localgot(); 96 break; 97 98 default: 99 break; 100 } 101 } 102 } 103 symbol_debug(s); 104 type_debug(s.Stype); 105 e = el_calloc(); 106 e.Eoper = OPvar; 107 e.EV.Vsym = s; 108 type_debug(s.Stype); 109 e.Ety = s.ty(); 110 if (s.Stype.Tty & mTYthread) 111 { 112 //printf("thread local %s\n", s.Sident); 113 if (config.exe & (EX_OSX | EX_OSX64)) 114 { 115 } 116 else if (config.exe & EX_posix) 117 { 118 /* For 32 bit: 119 * Generate for var locals: 120 * MOV reg,GS:[00000000] // add GS: override in back end 121 * ADD reg, offset s@TLS_LE 122 * e => *(&s + *(GS:0)) 123 * For var globals: 124 * MOV reg,GS:[00000000] 125 * ADD reg, s@TLS_IE 126 * e => *(s + *(GS:0)) 127 * note different fixup 128 ***************************************** 129 * For 64 bit: 130 * Generate for var locals: 131 * MOV reg,FS:s@TPOFF32 132 * For var globals: 133 * MOV RAX,s@GOTTPOFF[RIP] 134 * MOV reg,FS:[RAX] 135 * 136 * For address of locals: 137 * MOV RAX,FS:[00] 138 * LEA reg,s@TPOFF32[RAX] 139 * e => &s + *(FS:0) 140 * For address of globals: 141 * MOV reg,FS:[00] 142 * MOV RAX,s@GOTTPOFF[RIP] 143 * ADD reg,RAX 144 * e => s + *(FS:0) 145 * This leaves us with a problem, as the 'var' version cannot simply have 146 * its address taken, as what is the address of FS:s ? The (not so efficient) 147 * solution is to just use the second address form, and * it. 148 * Turns out that is identical to the 32 bit version, except GS => FS and the 149 * fixups are different. 150 * In the future, we should figure out a way to optimize to the 'var' version. 151 */ 152 if (I64) 153 Obj.refGOTsym(); 154 elem *e1 = el_calloc(); 155 e1.EV.Vsym = s; 156 if (s.Sclass == SCstatic || s.Sclass == SClocstat) 157 { 158 e1.Eoper = OPrelconst; 159 e1.Ety = TYnptr; 160 } 161 else 162 { 163 e1.Eoper = OPvar; 164 e1.Ety = TYnptr; 165 } 166 167 elem* e2 = el_una(OPind, TYsize, el_long(TYfgPtr, 0)); // I64: FS:[0000], I32: GS:[0000] 168 169 e.Eoper = OPind; 170 e.EV.E1 = el_bin(OPadd,e1.Ety,e2,e1); 171 e.EV.E2 = null; 172 } 173 else if (config.exe & EX_windos) 174 { 175 /* 176 Win32: 177 mov EAX,FS:__tls_array 178 mov ECX,__tls_index 179 mov EAX,[ECX*4][EAX] 180 inc dword ptr _t[EAX] 181 182 e => *(&s + *(FS:_tls_array + _tls_index * 4)) 183 184 If this is an executable app, not a dll, _tls_index 185 can be assumed to be 0. 186 187 Win64: 188 189 mov EAX,&s 190 mov RDX,GS:__tls_array 191 mov ECX,_tls_index[RIP] 192 mov RCX,[RCX*8][RDX] 193 mov EAX,[RCX][RAX] 194 195 e => *(&s + *(GS:[80] + _tls_index * 8)) 196 197 If this is an executable app, not a dll, _tls_index 198 can be assumed to be 0. 199 */ 200 elem* e1,e2,ea; 201 202 e1 = el_calloc(); 203 e1.Eoper = OPrelconst; 204 e1.EV.Vsym = s; 205 e1.Ety = TYnptr; 206 207 if (config.wflags & WFexe) 208 { 209 // e => *(&s + *(FS:_tls_array)) 210 e2 = el_var(getRtlsym(RTLSYM_TLS_ARRAY)); 211 } 212 else 213 { 214 e2 = el_bin(OPmul,TYint,el_var(getRtlsym(RTLSYM_TLS_INDEX)),el_long(TYint,REGSIZE)); 215 ea = el_var(getRtlsym(RTLSYM_TLS_ARRAY)); 216 e2 = el_bin(OPadd,ea.Ety,ea,e2); 217 } 218 e2 = el_una(OPind,TYsize_t,e2); 219 220 e.Eoper = OPind; 221 e.EV.E1 = el_bin(OPadd,e1.Ety,e1,e2); 222 e.EV.E2 = null; 223 } 224 } 225 return e; 226 } 227 } 228 229 version (SCPP_HTOD) 230 { 231 elem * el_var(Symbol *s) 232 { 233 elem *e; 234 235 //printf("el_var(s = '%s')\n", s.Sident); 236 if (config.exe & EX_posix) 237 { 238 if (config.flags3 & CFG3pic && !tyfunc(s.ty())) 239 return el_picvar(s); 240 } 241 symbol_debug(s); 242 type_debug(s.Stype); 243 e = el_calloc(); 244 e.Eoper = OPvar; 245 e.EV.Vsym = s; 246 247 version (SCPP_HTOD) 248 enum scpp = true; 249 else 250 enum scpp = false; 251 252 if (scpp && PARSER) 253 { 254 type *t = s.Stype; 255 type_debug(t); 256 e.ET = t; 257 t.Tcount++; 258 if (config.exe & EX_windos) 259 { 260 switch (t.Tty & (mTYimport | mTYthread)) 261 { 262 case mTYimport: 263 Obj._import(e); 264 break; 265 266 case mTYthread: 267 /* 268 mov EAX,FS:__tls_array 269 mov ECX,__tls_index 270 mov EAX,[ECX*4][EAX] 271 inc dword ptr _t[EAX] 272 273 e => *(&s + *(FS:_tls_array + _tls_index * 4)) 274 */ 275 version (MARS) 276 assert(0); 277 else 278 { 279 { 280 elem* e1,e2,ea; 281 e1 = el_calloc(); 282 e1.Eoper = OPrelconst; 283 e1.EV.Vsym = s; 284 e1.ET = newpointer(s.Stype); 285 e1.ET.Tcount++; 286 287 e2 = el_bint(OPmul,tstypes[TYint],el_var(getRtlsym(RTLSYM_TLS_INDEX)),el_longt(tstypes[TYint],4)); 288 ea = el_var(getRtlsym(RTLSYM_TLS_ARRAY)); 289 e2 = el_bint(OPadd,ea.ET,ea,e2); 290 e2 = el_unat(OPind,tstypes[TYint],e2); 291 292 e.Eoper = OPind; 293 e.EV.E1 = el_bint(OPadd,e1.ET,e1,e2); 294 e.EV.E2 = null; 295 } 296 } 297 break; 298 299 case mTYthread | mTYimport: 300 version (SCPP_HTOD) { } else assert(0); 301 tx86err(EM_thread_and_dllimport,s.Sident.ptr); // can't be both thread and import 302 break; 303 304 default: 305 break; 306 } 307 } 308 } 309 else 310 e.Ety = s.ty(); 311 return e; 312 } 313 } 314 315 /************************** 316 * Make a pointer to a `Symbol`. 317 * Params: s = symbol 318 * Returns: `elem` with address of `s` 319 */ 320 321 elem * el_ptr(Symbol *s) 322 { 323 //printf("el_ptr(s = '%s')\n", s.Sident.ptr); 324 //printf("el_ptr\n"); 325 symbol_debug(s); 326 type_debug(s.Stype); 327 328 const typtr = s.symbol_pointerType(); 329 330 if (config.exe & (EX_OSX | EX_OSX64)) 331 { 332 if (config.flags3 & CFG3pic && tyfunc(s.ty()) && I32) 333 { 334 /* Cannot access address of code from code. 335 * Instead, create a data variable, put the address of the 336 * code in that data variable, and return the elem for 337 * that data variable. 338 */ 339 Symbol *sd = symboldata(Offset(DATA), typtr); 340 sd.Sseg = DATA; 341 Obj.data_start(sd, _tysize[TYnptr], DATA); 342 Offset(DATA) += Obj.reftoident(DATA, Offset(DATA), s, 0, CFoff); 343 elem* e = el_picvar(sd); 344 e.Ety = typtr; 345 return e; 346 } 347 } 348 349 if (config.exe & EX_posix) 350 { 351 if (config.flags3 & CFG3pie && 352 s.Stype.Tty & mTYthread) 353 { 354 elem* e = el_pieptr(s); // Position Independent Executable 355 e.Ety = typtr; 356 return e; 357 } 358 359 if (config.flags3 & CFG3pie && 360 tyfunc(s.ty()) && 361 (s.Sclass == SCglobal || s.Sclass == SCcomdat || s.Sclass == SCcomdef || s.Sclass == SCextern)) 362 { 363 elem* e = el_calloc(); 364 e.Eoper = OPvar; 365 e.EV.Vsym = s; 366 if (I64) 367 e.Ety = typtr; 368 else if (I32) 369 { 370 e.Ety = TYnptr; 371 e.Eoper = OPrelconst; 372 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 373 e = el_una(OPind, typtr, e); 374 } 375 else 376 assert(0); 377 return e; 378 } 379 } 380 381 elem *e; 382 383 if (config.exe & EX_posix) 384 { 385 if (config.flags3 & CFG3pic && 386 tyfunc(s.ty())) 387 { 388 e = el_picvar(s); 389 } 390 else 391 e = el_var(s); 392 } 393 else 394 e = el_var(s); 395 396 version (SCPP_HTOD) 397 { 398 if (PARSER) 399 { type_debug(e.ET); 400 e = el_unat(OPaddr,type_ptr(e,e.ET),e); 401 return e; 402 } 403 } 404 405 if (e.Eoper == OPvar) 406 { 407 e.Ety = typtr; 408 e.Eoper = OPrelconst; 409 } 410 else 411 { 412 e = el_una(OPaddr, typtr, e); 413 e = doptelem(e, GOALvalue | GOALflags); 414 } 415 return e; 416 } 417 418 419 /*************************************** 420 * Allocate localgot symbol. 421 */ 422 423 private Symbol *el_alloc_localgot() 424 { 425 if (config.exe & EX_windos) 426 return null; 427 428 /* Since localgot is a local variable to each function, 429 * localgot must be set back to null 430 * at the start of code gen for each function. 431 */ 432 if (I32 && !localgot) 433 { 434 //printf("el_alloc_localgot()\n"); 435 char[15] name = void; 436 __gshared int tmpnum; 437 sprintf(name.ptr, "_LOCALGOT%d".ptr, tmpnum++); 438 type *t = type_fake(TYnptr); 439 /* Make it volatile because we need it for calling functions, but that isn't 440 * noticed by the data flow analysis. Hence, it may get deleted if we don't 441 * make it volatile. 442 */ 443 type_setcv(&t, mTYvolatile); 444 localgot = symbol_name(name.ptr, SCauto, t); 445 symbol_add(localgot); 446 localgot.Sfl = FLauto; 447 localgot.Sflags = SFLfree | SFLunambig | GTregcand; 448 } 449 return localgot; 450 } 451 452 453 /************************** 454 * Make an elem out of a symbol, PIC style. 455 */ 456 457 private elem *el_picvar(Symbol *s) 458 { 459 if (config.exe & (EX_OSX | EX_OSX64)) 460 return el_picvar_OSX(s); 461 else if (config.exe & EX_posix) 462 return el_picvar_posix(s); 463 assert(0); 464 } 465 466 private elem *el_picvar_OSX(Symbol *s) 467 { 468 elem *e; 469 int x; 470 471 //printf("el_picvar(s = '%s')", s.Sident); printf(" Sclass = "); WRclass((enum SC) s.Sclass); printf("\n"); 472 //symbol_print(s); 473 symbol_debug(s); 474 type_debug(s.Stype); 475 e = el_calloc(); 476 e.Eoper = OPvar; 477 e.EV.Vsym = s; 478 e.Ety = s.ty(); 479 480 switch (s.Sclass) 481 { 482 case SCstatic: 483 case SClocstat: 484 x = 0; 485 goto case_got; 486 487 case SCcomdat: 488 case SCcomdef: 489 if (0 && I64) 490 { 491 x = 0; 492 goto case_got; 493 } 494 goto case SCglobal; 495 496 case SCglobal: 497 case SCextern: 498 static if (0) 499 { 500 if (s.Stype.Tty & mTYthread) 501 x = 0; 502 else 503 x = 1; 504 } 505 else 506 x = 1; 507 508 case_got: 509 { 510 const op = e.Eoper; 511 tym_t tym = e.Ety; 512 e.Eoper = OPrelconst; 513 e.Ety = TYnptr; 514 if (I32) 515 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 516 static if (1) 517 { 518 if (I32 && s.Stype.Tty & mTYthread) 519 { 520 if (!tls_get_addr_sym) 521 { 522 /* void *___tls_get_addr(void *ptr); 523 * Parameter ptr is passed in RDI, matching TYnfunc calling convention. 524 */ 525 tls_get_addr_sym = symbol_name("___tls_get_addr",SCglobal,type_fake(TYnfunc)); 526 symbol_keep(tls_get_addr_sym); 527 } 528 if (x == 1) 529 e = el_una(OPind, TYnptr, e); 530 e = el_bin(OPcallns, TYnptr, el_var(tls_get_addr_sym), e); 531 if (op == OPvar) 532 e = el_una(OPind, TYnptr, e); 533 } 534 } 535 if (I64 || !(s.Stype.Tty & mTYthread)) 536 { 537 switch (op * 2 + x) 538 { 539 case OPvar * 2 + 1: 540 e = el_una(OPind, TYnptr, e); 541 e = el_una(OPind, TYnptr, e); 542 break; 543 544 case OPvar * 2 + 0: 545 case OPrelconst * 2 + 1: 546 e = el_una(OPind, TYnptr, e); 547 break; 548 549 case OPrelconst * 2 + 0: 550 break; 551 552 default: 553 assert(0); 554 } 555 } 556 static if (1) 557 { 558 /** 559 * A thread local variable is outputted like the following D struct: 560 * 561 * struct TLVDescriptor(T) 562 * { 563 * extern(C) T* function (TLVDescriptor*) thunk; 564 * size_t key; 565 * size_t offset; 566 * } 567 * 568 * To access the value of the variable, the variable is accessed 569 * like a plain global (__gshared) variable of the type 570 * TLVDescriptor. The thunk is called and a pointer to the variable 571 * itself is passed as the argument. The return value of the thunk 572 * is a pointer to the value of the thread local variable. 573 * 574 * module foo; 575 * 576 * int bar; 577 * pragma(mangle, "_D3foo3bari") extern __gshared TLVDescriptor!(int) barTLV; 578 * 579 * int a = *barTLV.thunk(&barTLV); 580 */ 581 if (I64 && s.Stype.Tty & mTYthread) 582 { 583 e = el_una(OPaddr, TYnptr, e); 584 e = el_bin(OPadd, TYnptr, e, el_long(TYullong, 0)); 585 e = el_una(OPind, TYnptr, e); 586 e = el_una(OPind, TYnfunc, e); 587 588 elem *e2 = el_calloc(); 589 e2.Eoper = OPvar; 590 e2.EV.Vsym = s; 591 e2.Ety = s.ty(); 592 e2.Eoper = OPrelconst; 593 e2.Ety = TYnptr; 594 595 e2 = el_una(OPind, TYnptr, e2); 596 e2 = el_una(OPind, TYnptr, e2); 597 e2 = el_una(OPaddr, TYnptr, e2); 598 e2 = doptelem(e2, GOALvalue | GOALflags); 599 e2 = el_bin(OPadd, TYnptr, e2, el_long(TYullong, 0)); 600 e2 = el_bin(OPcall, TYnptr, e, e2); 601 e2 = el_una(OPind, TYint, e2); 602 e = e2; 603 } 604 } 605 e.Ety = tym; 606 break; 607 } 608 default: 609 break; 610 } 611 return e; 612 } 613 614 private elem *el_picvar_posix(Symbol *s) 615 { 616 elem *e; 617 int x; 618 619 //printf("el_picvar(s = '%s')\n", s.Sident.ptr); 620 symbol_debug(s); 621 type_debug(s.Stype); 622 e = el_calloc(); 623 e.Eoper = OPvar; 624 e.EV.Vsym = s; 625 e.Ety = s.ty(); 626 627 /* For 32 bit PIC: 628 * CALL __i686.get_pc_thunk.bx@PC32 629 * ADD EBX,offset _GLOBAL_OFFSET_TABLE_@GOTPC[2] 630 * Generate for var locals: 631 * MOV reg,s@GOTOFF[014h][EBX] 632 * For var globals: 633 * MOV EAX,s@GOT32[EBX] 634 * MOV reg,[EAX] 635 * For TLS var locals and globals: 636 * LEA EAX,s@TLS_GD[1*EBX+0] // must use SIB addressing 637 * CALL ___tls_get_addr@PLT32 638 * MOV reg,[EAX] 639 ***************************************** 640 * Generate for var locals: 641 * MOV reg,s@PC32[RIP] 642 * For var globals: 643 * MOV RAX,s@GOTPCREL[RIP] 644 * MOV reg,[RAX] 645 * For TLS var locals and globals: 646 * 0x66 647 * LEA DI,s@TLSGD[RIP] 648 * 0x66 649 * 0x66 650 * 0x48 (REX | REX_W) 651 * CALL __tls_get_addr@PLT32 652 * MOV reg,[RAX] 653 */ 654 655 if (I64) 656 { 657 switch (s.Sclass) 658 { 659 case SCstatic: 660 case SClocstat: 661 x = 0; 662 goto case_got64; 663 664 case SCglobal: 665 if (config.flags3 & CFG3pie) 666 x = 0; 667 else 668 x = 1; 669 goto case_got64; 670 671 case SCcomdat: 672 case SCcomdef: 673 case SCextern: 674 x = 1; 675 goto case_got64; 676 677 case_got64: 678 { 679 Obj.refGOTsym(); 680 const op = e.Eoper; 681 tym_t tym = e.Ety; 682 e.Ety = TYnptr; 683 684 if (s.Stype.Tty & mTYthread) 685 { 686 /* Add "volatile" to prevent e from being common subexpressioned. 687 * This is so we can preserve the magic sequence of instructions 688 * that the gnu linker patches: 689 * lea EDI,x@tlsgd[RIP], call __tls_get_addr@plt 690 * => 691 * mov EAX,gs[0], sub EAX,x@tpoff 692 */ 693 e.Eoper = OPrelconst; 694 e.Ety |= mTYvolatile; 695 if (!tls_get_addr_sym) 696 { 697 /* void *__tls_get_addr(void *ptr); 698 * Parameter ptr is passed in RDI, matching TYnfunc calling convention. 699 */ 700 tls_get_addr_sym = symbol_name("__tls_get_addr",SCglobal,type_fake(TYnfunc)); 701 symbol_keep(tls_get_addr_sym); 702 } 703 e = el_bin(OPcall, TYnptr, el_var(tls_get_addr_sym), e); 704 } 705 706 switch (op * 2 + x) 707 { 708 case OPvar * 2 + 1: 709 e = el_una(OPind, TYnptr, e); 710 break; 711 712 case OPvar * 2 + 0: 713 case OPrelconst * 2 + 1: 714 break; 715 716 case OPrelconst * 2 + 0: 717 e = el_una(OPaddr, TYnptr, e); 718 break; 719 720 default: 721 assert(0); 722 } 723 e.Ety = tym; 724 } 725 break; 726 727 default: 728 break; 729 } 730 } 731 else 732 { 733 switch (s.Sclass) 734 { 735 /* local (and thread) symbols get only one level of indirection; 736 * all globally known symbols get two. 737 */ 738 case SCstatic: 739 case SClocstat: 740 x = 0; 741 goto case_got; 742 743 case SCglobal: 744 if (config.flags3 & CFG3pie) 745 x = 0; 746 else if (s.Stype.Tty & mTYthread) 747 x = 0; 748 else 749 x = 1; 750 goto case_got; 751 752 case SCcomdat: 753 case SCcomdef: 754 case SCextern: 755 if (s.Stype.Tty & mTYthread) 756 x = 0; 757 else 758 x = 1; 759 case_got: 760 { 761 const op = e.Eoper; 762 tym_t tym = e.Ety; 763 e.Eoper = OPrelconst; 764 e.Ety = TYnptr; 765 766 if (s.Stype.Tty & mTYthread) 767 { 768 /* Add "volatile" to prevent e from being common subexpressioned. 769 * This is so we can preserve the magic sequence of instructions 770 * that the gnu linker patches: 771 * lea EAX,x@tlsgd[1*EBX+0], call __tls_get_addr@plt 772 * => 773 * mov EAX,gs[0], sub EAX,x@tpoff 774 * elf32-i386.c 775 */ 776 e.Ety |= mTYvolatile; 777 if (!tls_get_addr_sym) 778 { 779 /* void *___tls_get_addr(void *ptr); 780 * Parameter ptr is passed in EAX, matching TYjfunc calling convention. 781 */ 782 tls_get_addr_sym = symbol_name("___tls_get_addr",SCglobal,type_fake(TYjfunc)); 783 symbol_keep(tls_get_addr_sym); 784 } 785 e = el_bin(OPcall, TYnptr, el_var(tls_get_addr_sym), e); 786 } 787 else 788 { 789 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 790 } 791 792 switch (op * 2 + x) 793 { 794 case OPvar * 2 + 1: 795 e = el_una(OPind, TYnptr, e); 796 e = el_una(OPind, TYnptr, e); 797 break; 798 799 case OPvar * 2 + 0: 800 case OPrelconst * 2 + 1: 801 e = el_una(OPind, TYnptr, e); 802 break; 803 804 case OPrelconst * 2 + 0: 805 break; 806 807 default: 808 assert(0); 809 } 810 e.Ety = tym; 811 break; 812 } 813 default: 814 break; 815 } 816 } 817 return e; 818 } 819 820 /********************************************** 821 * Create an elem for TLS variable `s`. 822 * Use PIE protocol. 823 * Params: s = variable's symbol 824 * Returns: elem created 825 */ 826 private elem *el_pievar(Symbol *s) 827 { 828 if (config.exe & (EX_OSX | EX_OSX64)) 829 assert(0); 830 831 int x; 832 833 //printf("el_pievar(s = '%s')\n", s.Sident.ptr); 834 symbol_debug(s); 835 type_debug(s.Stype); 836 auto e = el_calloc(); 837 e.Eoper = OPvar; 838 e.EV.Vsym = s; 839 e.Ety = s.ty(); 840 841 if (I64) 842 { 843 switch (s.Sclass) 844 { 845 case SCstatic: 846 case SClocstat: 847 case SCglobal: 848 break; 849 850 case SCcomdat: 851 case SCcomdef: 852 case SCextern: 853 { 854 /* Generate: 855 * mov RAX,extern_tls@GOTTPOFF[RIP] 856 * mov EAX,FS:[RAX] 857 */ 858 Obj.refGOTsym(); 859 tym_t tym = e.Ety; 860 e.Ety = TYfgPtr; 861 862 e = el_una(OPind, tym, e); 863 break; 864 } 865 default: 866 break; 867 } 868 } 869 else 870 { 871 switch (s.Sclass) 872 { 873 case SCstatic: 874 case SClocstat: 875 case SCglobal: 876 break; 877 878 case SCcomdat: 879 case SCcomdef: 880 case SCextern: 881 { 882 /* Generate: 883 * mov EAX,extern_tls@TLS_GOTIE[ECX] 884 * mov EAX,GS:[EAX] 885 */ 886 tym_t tym = e.Ety; 887 e.Eoper = OPrelconst; 888 e.Ety = TYnptr; 889 890 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 891 e = el_una(OPind, TYfgPtr, e); 892 e = el_una(OPind, tym, e); 893 break; 894 } 895 default: 896 break; 897 } 898 } 899 return e; 900 } 901 902 /********************************************** 903 * Create an address for TLS variable `s`. 904 * Use PIE protocol. 905 * Params: s = variable's symbol 906 * Returns: elem created 907 */ 908 private elem *el_pieptr(Symbol *s) 909 { 910 if (config.exe & (EX_OSX | EX_OSX64)) 911 assert(0); 912 913 int x; 914 915 //printf("el_pieptr(s = '%s')\n", s.Sident.ptr); 916 symbol_debug(s); 917 type_debug(s.Stype); 918 auto e = el_calloc(); 919 e.Eoper = OPrelconst; 920 e.EV.Vsym = s; 921 e.Ety = TYnptr; 922 923 elem* e0 = el_una(OPind, TYsize, el_long(TYfgPtr, 0)); // I64: FS:[0000], I32: GS:[0000] 924 925 if (I64) 926 { 927 Obj.refGOTsym(); // even though not used, generate reference to _GLOBAL_OFFSET_TABLE_ 928 switch (s.Sclass) 929 { 930 case SCstatic: 931 case SClocstat: 932 case SCglobal: 933 { 934 /* Generate: 935 * mov RAX,FS:[0000] 936 * add EAX,offset FLAG:global_tls@TPOFF32 937 */ 938 e = el_bin(OPadd, TYnptr, e0, e); 939 break; 940 } 941 942 case SCcomdat: 943 case SCcomdef: 944 case SCextern: 945 { 946 /* Generate: 947 * mov RAX,extern_tls@GOTTPOFF[RIP] 948 * mov RDX,FS:[0000] 949 * add RAX,EDX 950 */ 951 e.Eoper = OPvar; 952 e = el_bin(OPadd, TYnptr, e0, e); 953 break; 954 } 955 default: 956 break; 957 } 958 } 959 else 960 { 961 switch (s.Sclass) 962 { 963 case SCstatic: 964 case SClocstat: 965 { 966 /* Generate: 967 * mov LEA,global_tls@TLS_LE[ECX] 968 * mov EDX,GS:[0000] 969 * add EAX,EDX 970 */ 971 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 972 e = el_bin(OPadd, TYnptr, e, e0); 973 break; 974 } 975 976 case SCglobal: 977 { 978 /* Generate: 979 * mov EAX,global_tls@TLS_LE[ECX] 980 * mov EDX,GS:[0000] 981 * add EAX,EDX 982 */ 983 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 984 e = el_una(OPind, TYnptr, e); 985 e = el_bin(OPadd, TYnptr, e, e0); 986 break; 987 } 988 989 case SCcomdat: 990 case SCcomdef: 991 case SCextern: 992 { 993 /* Generate: 994 * mov EAX,extern_tls@TLS_GOTIE[ECX] 995 * mov EDX,GS:[0000] 996 * add EAX,EDX 997 */ 998 e = el_bin(OPadd, TYnptr, e, el_var(el_alloc_localgot())); 999 e = el_una(OPind, TYnptr, e); 1000 e = el_bin(OPadd, TYnptr, e, e0); 1001 break; 1002 } 1003 default: 1004 break; 1005 } 1006 } 1007 return e; 1008 } 1009 1010 1011 }