diff --git a/compiler/ogbase.pas b/compiler/ogbase.pas
index 95b643c368..6551ae0f3f 100644
--- a/compiler/ogbase.pas
+++ b/compiler/ogbase.pas
@@ -60,6 +60,8 @@ interface
          { PIC }
          RELOC_GOTPCREL,
          RELOC_PLT32,
+         RELOC_TLSGD,
+         RELOC_TPOFF,
 {$endif x86_64}
 {$ifdef i386}
          { PIC }
@@ -176,7 +178,9 @@ interface
        { Supports bss-like allocation of data, even though it is written in file (i.e. also has oso_Data) }
        oso_sparse_data,
        { Section to support the resolution of multiple symbols with the same name }
-       oso_comdat
+       oso_comdat,
+       { section containing thread variables }
+       oso_threadvar
      );
 
      TObjSectionOptions = set of TObjSectionOption;
@@ -1196,7 +1200,7 @@ implementation
           {roData} [oso_Data,oso_load,oso_write],
           {roData_norel} [oso_Data,oso_load],
           {bss} [oso_load,oso_write],
-          {threadvar} [oso_load,oso_write],
+          {threadvar} [oso_load,oso_write,oso_threadvar],
           {pdata} [oso_data,oso_load],
           {stub} [oso_Data,oso_load,oso_executable],
           {data_nonlazy}  [oso_Data,oso_load,oso_write],
diff --git a/compiler/ogelf.pas b/compiler/ogelf.pas
index 4b052cd3e9..17a6cef447 100644
--- a/compiler/ogelf.pas
+++ b/compiler/ogelf.pas
@@ -401,6 +401,8 @@ implementation
           Ashflags:=Ashflags or SHF_EXECINSTR;
         if oso_write in aoptions then
           Ashflags:=Ashflags or SHF_WRITE;
+        if oso_threadvar in aoptions then
+          Ashflags:=Ashflags or SHF_TLS;
       end;
 
 
@@ -419,6 +421,8 @@ implementation
           include(aoptions,oso_write);
         if Ashflags and SHF_EXECINSTR<>0 then
           include(aoptions,oso_executable);
+        if Ashflags and SHF_TLS<>0 then
+          include(aoptions,oso_threadvar);
       end;
 
 
@@ -575,6 +579,15 @@ implementation
                 result:=secname+'.'+aname;
                 exit;
               end;
+
+            if atype=sec_threadvar then
+              begin
+                if (target_info.system in (systems_windows+systems_wince)) then
+                  secname:='.tls'
+                else if (target_info.system in systems_linux) then
+                  secname:='.tbss';
+              end;
+
             if create_smartlink_sections and (aname<>'') then
               begin
                 case aorder of
@@ -653,7 +666,7 @@ implementation
         if assigned(objreloc) then
           begin
             objreloc.size:=len;
-            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_GOTPCREL{$endif}] then
+            if reltype in [RELOC_RELATIVE{$ifdef x86},RELOC_PLT32{$endif}{$ifdef x86_64},RELOC_GOTPCREL,RELOC_TLSGD{$endif}] then
               dec(data,len);
             if ElfTarget.relocs_use_addend then
               begin
diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas
index 422ba3f1c8..d174a8cc97 100644
--- a/compiler/x86/aasmcpu.pas
+++ b/compiler/x86/aasmcpu.pas
@@ -1510,7 +1510,7 @@ implementation
                 end;
               top_ref :
                 begin
-                  if (ref^.refaddr=addr_no)
+                  if (ref^.refaddr in [addr_no{$ifdef x86_64},addr_tpoff{$endif x86_64}])
 {$ifdef i386}
                      or (
                          (ref^.refaddr in [addr_pic]) and
@@ -1519,7 +1519,7 @@ implementation
 {$endif i386}
 {$ifdef x86_64}
                      or (
-                         (ref^.refaddr in [addr_pic,addr_pic_no_got]) and
+                         (ref^.refaddr in [addr_pic,addr_pic_no_got,addr_tlsgd]) and
                          (ref^.base<>NR_NO)
                         )
 {$endif x86_64}
@@ -3592,6 +3592,18 @@ implementation
                       currabsreloc:=RELOC_RELATIVE;
                       currabsreloc32:=RELOC_RELATIVE;
                     end
+                  else if oper[opidx]^.ref^.refaddr=addr_tpoff then
+                    begin
+                      currrelreloc:=RELOC_TPOFF;
+                      currabsreloc:=RELOC_TPOFF;
+                      currabsreloc32:=RELOC_TPOFF;
+                    end
+                  else if oper[opidx]^.ref^.refaddr=addr_tlsgd then
+                    begin
+                      currrelreloc:=RELOC_TLSGD;
+                      currabsreloc:=RELOC_TLSGD;
+                      currabsreloc32:=RELOC_TLSGD;
+                    end
                   else
 {$endif x86_64}
                     begin
@@ -3630,22 +3642,22 @@ implementation
        procedure objdata_writereloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
          begin
 {$ifdef i386}
-               { Special case of '_GLOBAL_OFFSET_TABLE_'
-                 which needs a special relocation type R_386_GOTPC }
-               if assigned (p) and
-                  (p.name='_GLOBAL_OFFSET_TABLE_') and
-                  (tf_pic_uses_got in target_info.flags) then
-                 begin
-                   { nothing else than a 4 byte relocation should occur
-                     for GOT }
-                   if len<>4 then
-                     Message1(asmw_e_invalid_opcode_and_operands,GetString);
-                   Reloctype:=RELOC_GOTPC;
-                   { We need to add the offset of the relocation
-                     of _GLOBAL_OFFSET_TABLE symbol within
-                     the current instruction }
-                   inc(data,objdata.currobjsec.size-insoffset);
-                 end;
+           { Special case of '_GLOBAL_OFFSET_TABLE_'
+             which needs a special relocation type R_386_GOTPC }
+           if assigned (p) and
+              (p.name='_GLOBAL_OFFSET_TABLE_') and
+              (tf_pic_uses_got in target_info.flags) then
+             begin
+               { nothing else than a 4 byte relocation should occur
+                 for GOT }
+               if len<>4 then
+                 Message1(asmw_e_invalid_opcode_and_operands,GetString);
+               Reloctype:=RELOC_GOTPC;
+               { We need to add the offset of the relocation
+                 of _GLOBAL_OFFSET_TABLE symbol within
+                 the current instruction }
+               inc(data,objdata.currobjsec.size-insoffset);
+             end;
 {$endif i386}
            objdata.writereloc(data,len,p,Reloctype);
          end;
@@ -4534,6 +4546,10 @@ implementation
 {$ifdef x86_64}
                          if oper[opidx]^.ref^.refaddr=addr_pic then
                            currabsreloc:=RELOC_GOTPCREL
+                         else if oper[opidx]^.ref^.refaddr=addr_tlsgd then
+                           currabsreloc:=RELOC_TLSGD
+                         else if oper[opidx]^.ref^.refaddr=addr_tpoff then
+                           currabsreloc:=RELOC_TPOFF
                          else
                            if oper[opidx]^.ref^.base=NR_RIP then
                              begin
diff --git a/compiler/x86_64/cpuelf.pas b/compiler/x86_64/cpuelf.pas
index 7dacd47534..72920f2e2f 100644
--- a/compiler/x86_64/cpuelf.pas
+++ b/compiler/x86_64/cpuelf.pas
@@ -171,6 +171,15 @@ implementation
           result:=R_X86_64_GOTPCREL;
         RELOC_PLT32 :
           result:=R_X86_64_PLT32;
+        RELOC_TPOFF:
+          if objrel.size=8 then
+            result:=R_X86_64_TPOFF64
+          else if objrel.size=4 then
+            result:=R_X86_64_TPOFF32
+          else
+            InternalError(2019091701);
+        RELOC_TLSGD:
+          result:=R_X86_64_TLSGD
       else
         result:=0;
         InternalError(2012082302);