"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/dmd/dmd/backend/elpicpie.d" (20 Nov 2020, 28014 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    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 }