Răsfoiți Sursa

* do not create a global symbol in the middle of ansi/unicodestring
constants on Darwin, because its linker uses global symbols as delimiters
of subsections for dead code stripping. This was previously solved by
never making any ansistring constants smart linkable, which is now
solved

git-svn-id: trunk@21328 -

Jonas Maebe 13 ani în urmă
părinte
comite
8282d6e37a
4 a modificat fișierele cu 157 adăugiri și 70 ștergeri
  1. 96 37
      compiler/asmutils.pas
  2. 9 6
      compiler/cresstr.pas
  3. 31 15
      compiler/ncgcon.pas
  4. 21 12
      compiler/ngtcon.pas

+ 96 - 37
compiler/asmutils.pas

@@ -28,11 +28,19 @@ interface
 uses
 uses
   globtype,
   globtype,
   aasmbase,
   aasmbase,
-  aasmdata;
+  aasmdata,
+  symconst;
 
 
+    type
+      tasmlabofs = record
+        lab: tasmlabel;
+        ofs: pint;
+      end;
+
+    function emit_ansistring_const(list:TAsmList;data:PChar;len:LongInt;encoding:tstringencoding;NewSection:Boolean=True):tasmlabofs;
+    function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):tasmlabofs;
 
 
-    function emit_ansistring_const(list:TAsmList;data:PChar;len:LongInt;encoding:tstringencoding;NewSection:Boolean=True):TAsmLabel;
-    function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):TAsmLabel;
+    function get_string_symofs(typ: tstringtype; winlikewidestring: boolean): pint;
 
 
 
 
 implementation
 implementation
@@ -45,35 +53,40 @@ uses
   widestr,
   widestr,
   symdef;
   symdef;
 
 
-    function emit_ansistring_const(list:TAsmList;data:PChar;len:LongInt;encoding:tstringencoding;NewSection:Boolean): TAsmLabel;
+    function emit_ansistring_const(list:TAsmList;data:PChar;len:LongInt;encoding:tstringencoding;NewSection:Boolean): tasmlabofs;
       var
       var
-        referencelab: TAsmLabel;
         s: PChar;
         s: PChar;
       begin
       begin
-        current_asmdata.getdatalabel(result);
+        current_asmdata.getdatalabel(result.lab);
+        result.ofs:=0;
         if NewSection then
         if NewSection then
-          new_section(list,sec_rodata,result.name,const_align(sizeof(pint)));
-        referencelab := nil;
+          new_section(list,sec_rodata,result.lab.name,const_align(sizeof(pint)));
+        { put label before header on Darwin, because there the linker considers
+          a global symbol to be the start of a new subsection }
         if target_info.system in systems_darwin then
         if target_info.system in systems_darwin then
-          begin
-            current_asmdata.getdatalabel(referencelab);
-            list.concat(tai_label.create(referencelab));
-          end;
+          list.concat(tai_label.create(result.lab));
         list.concat(tai_const.create_16bit(encoding));
         list.concat(tai_const.create_16bit(encoding));
+        inc(result.ofs,2);
         list.concat(tai_const.create_16bit(1));
         list.concat(tai_const.create_16bit(1));
+        inc(result.ofs,2);
 {$ifdef cpu64bitaddr}
 {$ifdef cpu64bitaddr}
         { dummy for alignment }
         { dummy for alignment }
         list.concat(tai_const.create_32bit(0));
         list.concat(tai_const.create_32bit(0));
+        inc(result.ofs,4);
 {$endif cpu64bitaddr}
 {$endif cpu64bitaddr}
         list.concat(tai_const.create_pint(-1));
         list.concat(tai_const.create_pint(-1));
+        inc(result.ofs,sizeof(pint));
         list.concat(tai_const.create_pint(len));
         list.concat(tai_const.create_pint(len));
-        { make sure the string doesn't get dead stripped if the header is referenced }
-        if target_info.system in systems_darwin then
-          list.concat(tai_directive.create(asd_reference,result.name));
-        list.concat(tai_label.create(result));
-        { and vice versa }
-        if target_info.system in systems_darwin then
-          list.concat(tai_directive.create(asd_reference,referencelab.name));
+        inc(result.ofs,sizeof(pint));
+        if not(target_info.system in systems_darwin) then
+          begin
+            { results in slightly more efficient code }
+            list.concat(tai_label.create(result.lab));
+            result.ofs:=0;
+          end;
+        { sanity check }
+        if result.ofs<>get_string_symofs(st_ansistring,false) then
+          internalerror(2012051701);
 
 
         getmem(s,len+1);
         getmem(s,len+1);
         move(data^,s^,len);
         move(data^,s^,len);
@@ -82,40 +95,51 @@ uses
       end;
       end;
 
 
 
 
-    function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):TAsmLabel;
+    function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):tasmlabofs;
       var
       var
-        referencelab: TAsmLabel;
         i, strlength: SizeInt;
         i, strlength: SizeInt;
       begin
       begin
-        current_asmdata.getdatalabel(result);
-        new_section(list,sec_rodata,result.name,const_align(sizeof(pint)));
-        referencelab := nil;
-        if target_info.system in systems_darwin then
-          begin
-            current_asmdata.getdatalabel(referencelab);
-            list.concat(tai_label.create(referencelab));
-          end;
+        current_asmdata.getdatalabel(result.lab);
+        result.ofs:=0;
+        new_section(list,sec_rodata,result.lab.name,const_align(sizeof(pint)));
         strlength := getlengthwidestring(pcompilerwidestring(data));
         strlength := getlengthwidestring(pcompilerwidestring(data));
         if Winlike then
         if Winlike then
-          list.concat(Tai_const.Create_32bit(strlength*cwidechartype.size))
+          begin
+            list.concat(Tai_const.Create_32bit(strlength*cwidechartype.size));
+            { don't increase result.ofs, this is how Windows widestrings are
+              defined by the OS: a pointer 4 bytes past the length of the
+              string }
+            list.concat(Tai_label.Create(result.lab));
+          end
         else
         else
           begin
           begin
+            { put label before header on Darwin, because there the linker considers
+              a global symbol to be the start of a new subsection }
+            if target_info.system in systems_darwin then
+              list.concat(Tai_label.Create(result.lab));
             list.concat(tai_const.create_16bit(encoding));
             list.concat(tai_const.create_16bit(encoding));
+            inc(result.ofs,2);
             list.concat(tai_const.create_16bit(2));
             list.concat(tai_const.create_16bit(2));
+            inc(result.ofs,2);
     {$ifdef cpu64bitaddr}
     {$ifdef cpu64bitaddr}
             { dummy for alignment }
             { dummy for alignment }
             list.concat(Tai_const.Create_32bit(0));
             list.concat(Tai_const.Create_32bit(0));
+            inc(result.ofs,4);
     {$endif cpu64bitaddr}
     {$endif cpu64bitaddr}
             list.concat(Tai_const.Create_pint(-1));
             list.concat(Tai_const.Create_pint(-1));
+            inc(result.ofs,sizeof(pint));
             list.concat(Tai_const.Create_pint(strlength));
             list.concat(Tai_const.Create_pint(strlength));
+            inc(result.ofs,sizeof(pint));
+            if not(target_info.system in systems_darwin) then
+              begin
+                { results in slightly more efficient code }
+                list.concat(tai_label.create(result.lab));
+                result.ofs:=0;
+              end;
+            { sanity check }
+            if result.ofs<>get_string_symofs(st_unicodestring,false) then
+              internalerror(2012051702);
           end;
           end;
-        { make sure the string doesn't get dead stripped if the header is referenced }
-        if (target_info.system in systems_darwin) then
-          list.concat(tai_directive.create(asd_reference,result.name));
-        list.concat(Tai_label.Create(result));
-        { ... and vice versa }
-        if (target_info.system in systems_darwin) then
-          list.concat(tai_directive.create(asd_reference,referencelab.name));
         if cwidechartype.size = 2 then
         if cwidechartype.size = 2 then
           begin
           begin
             for i:=0 to strlength-1 do
             for i:=0 to strlength-1 do
@@ -128,4 +152,39 @@ uses
       end;
       end;
 
 
 
 
+    function get_string_symofs(typ: tstringtype; winlikewidestring: boolean): pint;
+      const
+        ansistring_header_size =
+          { encoding }
+          2 +
+          { elesize }
+          2 +
+{$ifdef cpu64bitaddr}
+          { alignment }
+          4 +
+{$endif cpu64bitaddr}
+          { reference count }
+          sizeof(pint) +
+          { length }
+          sizeof(pint);
+        unicodestring_header_size = ansistring_header_size;
+      begin
+        if not(target_info.system in systems_darwin) then
+          result:=0
+        else case typ of
+          st_ansistring:
+            result:=ansistring_header_size;
+          st_unicodestring:
+            result:=unicodestring_header_size;
+          st_widestring:
+            if winlikewidestring then
+              result:=0
+            else
+              result:=unicodestring_header_size;
+          else
+            result:=0;
+        end;
+      end;
+
+
 end.
 end.

+ 9 - 6
compiler/cresstr.pas

@@ -133,7 +133,7 @@ uses
     procedure Tresourcestrings.CreateResourceStringData;
     procedure Tresourcestrings.CreateResourceStringData;
       Var
       Var
         namelab,
         namelab,
-        valuelab : tasmlabel;
+        valuelab : tasmlabofs;
         resstrlab : tasmsymbol;
         resstrlab : tasmsymbol;
         endsymlab : tasmsymbol;
         endsymlab : tasmsymbol;
         R : TResourceStringItem;
         R : TResourceStringItem;
@@ -151,7 +151,7 @@ uses
 
 
         { Write unitname entry }
         { Write unitname entry }
         namelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],@current_module.localsymtable.name^[1],length(current_module.localsymtable.name^),getansistringcodepage,False);
         namelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],@current_module.localsymtable.name^[1],length(current_module.localsymtable.name^),getansistringcodepage,False);
-        current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(namelab));
+        current_asmdata.asmlists[al_resourcestrings].concat(tai_const.Create_sym_offset(namelab.lab,namelab.ofs));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(nil));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(nil));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(nil));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(nil));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(0));
         current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(0));
@@ -168,7 +168,10 @@ uses
             if assigned(R.value) and (R.len<>0) then
             if assigned(R.value) and (R.len<>0) then
               valuelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],R.Value,R.Len,getansistringcodepage,False)
               valuelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],R.Value,R.Len,getansistringcodepage,False)
             else
             else
-              valuelab:=nil;
+              begin
+                valuelab.lab:=nil;
+                valuelab.ofs:=0;
+              end;
             { Append the name as a ansistring. }
             { Append the name as a ansistring. }
             current_asmdata.asmlists[al_const].concat(cai_align.Create(const_align(sizeof(pint))));
             current_asmdata.asmlists[al_const].concat(cai_align.Create(const_align(sizeof(pint))));
             namelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],@R.Name[1],length(R.name),getansistringcodepage,False);
             namelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],@R.Name[1],length(R.name),getansistringcodepage,False);
@@ -185,9 +188,9 @@ uses
             new_section(current_asmdata.asmlists[al_resourcestrings],sec_data,make_mangledname('RESSTR',current_module.localsymtable,'2_'+r.name),sizeof(pint));
             new_section(current_asmdata.asmlists[al_resourcestrings],sec_data,make_mangledname('RESSTR',current_module.localsymtable,'2_'+r.name),sizeof(pint));
             resstrlab:=current_asmdata.DefineAsmSymbol(make_mangledname('RESSTR',R.Sym.owner,R.Sym.name),AB_GLOBAL,AT_DATA);
             resstrlab:=current_asmdata.DefineAsmSymbol(make_mangledname('RESSTR',R.Sym.owner,R.Sym.name),AB_GLOBAL,AT_DATA);
             current_asmdata.asmlists[al_resourcestrings].concat(tai_symbol.Create_global(resstrlab,0));
             current_asmdata.asmlists[al_resourcestrings].concat(tai_symbol.Create_global(resstrlab,0));
-            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(namelab));
-            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(valuelab));
-            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(valuelab));
+            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.Create_sym_offset(namelab.lab,namelab.ofs));
+            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.Create_sym_offset(valuelab.lab,valuelab.ofs));
+            current_asmdata.asmlists[al_resourcestrings].concat(tai_const.Create_sym_offset(valuelab.lab,valuelab.ofs));
             current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(longint(R.Hash)));
             current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(longint(R.Hash)));
 {$ifdef cpu64bitaddr}
 {$ifdef cpu64bitaddr}
             current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(0));
             current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_32bit(0));

+ 31 - 15
compiler/ncgcon.pas

@@ -257,12 +257,13 @@ implementation
 
 
     procedure tcgstringconstnode.pass_generate_code;
     procedure tcgstringconstnode.pass_generate_code;
       var
       var
-         lastlabel: tasmlabel;
+         lastlabel: tasmlabofs;
          pc: pchar;
          pc: pchar;
          l: longint;
          l: longint;
          href: treference;
          href: treference;
          pool: THashSet;
          pool: THashSet;
          entry: PHashSetItem;
          entry: PHashSetItem;
+         winlikewidestring: boolean;
 
 
       const
       const
         PoolMap: array[tconststringtype] of TConstPoolType = (
         PoolMap: array[tconststringtype] of TConstPoolType = (
@@ -281,6 +282,7 @@ implementation
             location.value:=0;
             location.value:=0;
             exit;
             exit;
           end;
           end;
+         winlikewidestring:=(cst_type=cst_widestring) and (tf_winlikewidestring in target_info.flags);
          { const already used ? }
          { const already used ? }
          if not assigned(lab_str) then
          if not assigned(lab_str) then
            begin
            begin
@@ -305,7 +307,13 @@ implementation
                            if len=0 then
                            if len=0 then
                              InternalError(2008032301)   { empty string should be handled above }
                              InternalError(2008032301)   { empty string should be handled above }
                            else
                            else
-                             lastlabel:=emit_ansistring_const(current_asmdata.AsmLists[al_typedconsts],value_str,len,tstringdef(resultdef).encoding);
+                             begin
+                               lastlabel:=emit_ansistring_const(current_asmdata.AsmLists[al_typedconsts],value_str,len,tstringdef(resultdef).encoding);
+                               { because we hardcode the offset below due to it
+                                 not being stored in the hashset, check here }
+                               if lastlabel.ofs<>get_string_symofs(st_ansistring,false) then
+                                 internalerror(2012051703);
+                             end;
                         end;
                         end;
                       cst_unicodestring,
                       cst_unicodestring,
                       cst_widestring:
                       cst_widestring:
@@ -313,18 +321,24 @@ implementation
                            if len=0 then
                            if len=0 then
                              InternalError(2008032302)   { empty string should be handled above }
                              InternalError(2008032302)   { empty string should be handled above }
                            else
                            else
-                             lastlabel := emit_unicodestring_const(current_asmdata.AsmLists[al_typedconsts],
-                                             value_str,
-                                             tstringdef(resultdef).encoding,
-                                             (cst_type=cst_widestring) and (tf_winlikewidestring in target_info.flags));
+                             begin
+                               lastlabel := emit_unicodestring_const(current_asmdata.AsmLists[al_typedconsts],
+                                               value_str,
+                                               tstringdef(resultdef).encoding,
+                                               winlikewidestring);
+                               { because we hardcode the offset below due to it
+                                 not being stored in the hashset, check here }
+                               if lastlabel.ofs<>get_string_symofs(tstringdef(resultdef).stringtype,winlikewidestring) then
+                                 internalerror(2012051704);
+                             end;
                         end;
                         end;
                       cst_shortstring:
                       cst_shortstring:
                         begin
                         begin
-                          current_asmdata.getdatalabel(lastlabel);
+                          current_asmdata.getdatalabel(lastlabel.lab);
                           maybe_new_object_file(current_asmdata.asmlists[al_typedconsts]);
                           maybe_new_object_file(current_asmdata.asmlists[al_typedconsts]);
-                          new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,lastlabel.name,const_align(sizeof(pint)));
+                          new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,lastlabel.lab.name,const_align(sizeof(pint)));
 
 
-                          current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(lastlabel));
+                          current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(lastlabel.lab));
                           { truncate strings larger than 255 chars }
                           { truncate strings larger than 255 chars }
                           if len>255 then
                           if len>255 then
                            l:=255
                            l:=255
@@ -339,11 +353,11 @@ implementation
                         end;
                         end;
                       cst_conststring:
                       cst_conststring:
                         begin
                         begin
-                          current_asmdata.getdatalabel(lastlabel);
+                          current_asmdata.getdatalabel(lastlabel.lab);
                           maybe_new_object_file(current_asmdata.asmlists[al_typedconsts]);
                           maybe_new_object_file(current_asmdata.asmlists[al_typedconsts]);
-                          new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,lastlabel.name,const_align(sizeof(pint)));
+                          new_section(current_asmdata.asmlists[al_typedconsts],sec_rodata_norel,lastlabel.lab.name,const_align(sizeof(pint)));
 
 
-                          current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(lastlabel));
+                          current_asmdata.asmlists[al_typedconsts].concat(Tai_label.Create(lastlabel.lab));
                           { include terminating zero }
                           { include terminating zero }
                           getmem(pc,len+1);
                           getmem(pc,len+1);
                           move(value_str^,pc[0],len);
                           move(value_str^,pc[0],len);
@@ -351,14 +365,16 @@ implementation
                           current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create_pchar(pc,len+1));
                           current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create_pchar(pc,len+1));
                         end;
                         end;
                    end;
                    end;
-                   lab_str:=lastlabel;
-                   entry^.Data:=lastlabel;
+                   lab_str:=lastlabel.lab;
+                   entry^.Data:=lastlabel.lab;
                 end;
                 end;
            end;
            end;
          if cst_type in [cst_ansistring, cst_widestring, cst_unicodestring] then
          if cst_type in [cst_ansistring, cst_widestring, cst_unicodestring] then
            begin
            begin
              location_reset(location, LOC_REGISTER, OS_ADDR);
              location_reset(location, LOC_REGISTER, OS_ADDR);
-             reference_reset_symbol(href, lab_str, 0, const_align(sizeof(pint)));
+             reference_reset_symbol(href, lab_str,
+               get_string_symofs(tstringdef(resultdef).stringtype,winlikewidestring),
+               const_align(sizeof(pint)));
              location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
              location.register:=cg.getaddressregister(current_asmdata.CurrAsmList);
              cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
              cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
            end
            end

+ 21 - 12
compiler/ngtcon.pas

@@ -437,7 +437,7 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
         strlength : aint;
         strlength : aint;
         strval    : pchar;
         strval    : pchar;
         strch     : char;
         strch     : char;
-        ll        : tasmlabel;
+        ll        : tasmlabofs;
         ca        : pchar;
         ca        : pchar;
         winlike   : boolean;
         winlike   : boolean;
         hsym      : tconstsym;
         hsym      : tconstsym;
@@ -533,21 +533,27 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
                 begin
                 begin
                    { an empty ansi string is nil! }
                    { an empty ansi string is nil! }
                    if (strlength=0) then
                    if (strlength=0) then
-                     ll := nil
+                     begin
+                       ll.lab:=nil;
+                       ll.ofs:=0;
+                     end
                    else
                    else
-                     ll := emit_ansistring_const(current_asmdata.asmlists[al_const],strval,strlength,def.encoding);
-                   list.concat(Tai_const.Create_sym(ll));
+                     ll:=emit_ansistring_const(current_asmdata.asmlists[al_const],strval,strlength,def.encoding);
+                   list.concat(Tai_const.Create_sym_offset(ll.lab,ll.ofs));
                 end;
                 end;
               st_unicodestring,
               st_unicodestring,
               st_widestring:
               st_widestring:
                 begin
                 begin
                    { an empty wide/unicode string is nil! }
                    { an empty wide/unicode string is nil! }
                    if (strlength=0) then
                    if (strlength=0) then
-                     ll := nil
+                     begin
+                       ll.lab:=nil;
+                       ll.ofs:=0;
+                     end
                    else
                    else
                      begin
                      begin
-                       winlike := (def.stringtype=st_widestring) and (tf_winlikewidestring in target_info.flags);
-                       ll := emit_unicodestring_const(current_asmdata.asmlists[al_const],
+                       winlike:=(def.stringtype=st_widestring) and (tf_winlikewidestring in target_info.flags);
+                       ll:=emit_unicodestring_const(current_asmdata.asmlists[al_const],
                               strval,
                               strval,
                               def.encoding,
                               def.encoding,
                               winlike);
                               winlike);
@@ -556,17 +562,20 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
                          Local initialized vars are excluded because they are initialized
                          Local initialized vars are excluded because they are initialized
                          at function entry instead. }
                          at function entry instead. }
                        if winlike and
                        if winlike and
-                          ((tcsym.owner.symtablelevel <= main_program_level) or
+                          ((tcsym.owner.symtablelevel<=main_program_level) or
                            (current_old_block_type=bt_const)) then
                            (current_old_block_type=bt_const)) then
                          begin
                          begin
+                           if ll.ofs<>0 then
+                             internalerror(2012051704);
                            current_asmdata.WideInits.Concat(
                            current_asmdata.WideInits.Concat(
-                              TTCInitItem.Create(tcsym, curoffset, ll)
+                              TTCInitItem.Create(tcsym,curoffset,ll.lab)
                            );
                            );
-                           ll := nil;
-                           Include(tcsym.varoptions, vo_force_finalize);
+                           ll.lab:=nil;
+                           ll.ofs:=0;
+                           Include(tcsym.varoptions,vo_force_finalize);
                          end;
                          end;
                      end;
                      end;
-                   list.concat(Tai_const.Create_sym(ll));
+                   list.concat(Tai_const.Create_sym_offset(ll.lab,ll.ofs));
                 end;
                 end;
               else
               else
                 internalerror(200107081);
                 internalerror(200107081);