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