Browse Source

* 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 năm trước cách đây
mục cha
commit
8282d6e37a
4 tập tin đã thay đổi với 157 bổ sung70 xóa
  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
   globtype,
   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
@@ -45,35 +53,40 @@ uses
   widestr,
   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
-        referencelab: TAsmLabel;
         s: PChar;
       begin
-        current_asmdata.getdatalabel(result);
+        current_asmdata.getdatalabel(result.lab);
+        result.ofs:=0;
         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
-          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));
+        inc(result.ofs,2);
         list.concat(tai_const.create_16bit(1));
+        inc(result.ofs,2);
 {$ifdef cpu64bitaddr}
         { dummy for alignment }
         list.concat(tai_const.create_32bit(0));
+        inc(result.ofs,4);
 {$endif cpu64bitaddr}
         list.concat(tai_const.create_pint(-1));
+        inc(result.ofs,sizeof(pint));
         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);
         move(data^,s^,len);
@@ -82,40 +95,51 @@ uses
       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
-        referencelab: TAsmLabel;
         i, strlength: SizeInt;
       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));
         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
           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));
+            inc(result.ofs,2);
             list.concat(tai_const.create_16bit(2));
+            inc(result.ofs,2);
     {$ifdef cpu64bitaddr}
             { dummy for alignment }
             list.concat(Tai_const.Create_32bit(0));
+            inc(result.ofs,4);
     {$endif cpu64bitaddr}
             list.concat(Tai_const.Create_pint(-1));
+            inc(result.ofs,sizeof(pint));
             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;
-        { 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
           begin
             for i:=0 to strlength-1 do
@@ -128,4 +152,39 @@ uses
       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.

+ 9 - 6
compiler/cresstr.pas

@@ -133,7 +133,7 @@ uses
     procedure Tresourcestrings.CreateResourceStringData;
       Var
         namelab,
-        valuelab : tasmlabel;
+        valuelab : tasmlabofs;
         resstrlab : tasmsymbol;
         endsymlab : tasmsymbol;
         R : TResourceStringItem;
@@ -151,7 +151,7 @@ uses
 
         { Write unitname entry }
         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_32bit(0));
@@ -168,7 +168,10 @@ uses
             if assigned(R.value) and (R.len<>0) then
               valuelab:=emit_ansistring_const(current_asmdata.asmlists[al_const],R.Value,R.Len,getansistringcodepage,False)
             else
-              valuelab:=nil;
+              begin
+                valuelab.lab:=nil;
+                valuelab.ofs:=0;
+              end;
             { Append the name as a ansistring. }
             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);
@@ -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));
             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_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)));
 {$ifdef cpu64bitaddr}
             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;
       var
-         lastlabel: tasmlabel;
+         lastlabel: tasmlabofs;
          pc: pchar;
          l: longint;
          href: treference;
          pool: THashSet;
          entry: PHashSetItem;
+         winlikewidestring: boolean;
 
       const
         PoolMap: array[tconststringtype] of TConstPoolType = (
@@ -281,6 +282,7 @@ implementation
             location.value:=0;
             exit;
           end;
+         winlikewidestring:=(cst_type=cst_widestring) and (tf_winlikewidestring in target_info.flags);
          { const already used ? }
          if not assigned(lab_str) then
            begin
@@ -305,7 +307,13 @@ implementation
                            if len=0 then
                              InternalError(2008032301)   { empty string should be handled above }
                            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;
                       cst_unicodestring,
                       cst_widestring:
@@ -313,18 +321,24 @@ implementation
                            if len=0 then
                              InternalError(2008032302)   { empty string should be handled above }
                            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;
                       cst_shortstring:
                         begin
-                          current_asmdata.getdatalabel(lastlabel);
+                          current_asmdata.getdatalabel(lastlabel.lab);
                           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 }
                           if len>255 then
                            l:=255
@@ -339,11 +353,11 @@ implementation
                         end;
                       cst_conststring:
                         begin
-                          current_asmdata.getdatalabel(lastlabel);
+                          current_asmdata.getdatalabel(lastlabel.lab);
                           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 }
                           getmem(pc,len+1);
                           move(value_str^,pc[0],len);
@@ -351,14 +365,16 @@ implementation
                           current_asmdata.asmlists[al_typedconsts].concat(Tai_string.Create_pchar(pc,len+1));
                         end;
                    end;
-                   lab_str:=lastlabel;
-                   entry^.Data:=lastlabel;
+                   lab_str:=lastlabel.lab;
+                   entry^.Data:=lastlabel.lab;
                 end;
            end;
          if cst_type in [cst_ansistring, cst_widestring, cst_unicodestring] then
            begin
              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);
              cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,href,location.register);
            end

+ 21 - 12
compiler/ngtcon.pas

@@ -437,7 +437,7 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
         strlength : aint;
         strval    : pchar;
         strch     : char;
-        ll        : tasmlabel;
+        ll        : tasmlabofs;
         ca        : pchar;
         winlike   : boolean;
         hsym      : tconstsym;
@@ -533,21 +533,27 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
                 begin
                    { an empty ansi string is nil! }
                    if (strlength=0) then
-                     ll := nil
+                     begin
+                       ll.lab:=nil;
+                       ll.ofs:=0;
+                     end
                    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;
               st_unicodestring,
               st_widestring:
                 begin
                    { an empty wide/unicode string is nil! }
                    if (strlength=0) then
-                     ll := nil
+                     begin
+                       ll.lab:=nil;
+                       ll.ofs:=0;
+                     end
                    else
                      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,
                               def.encoding,
                               winlike);
@@ -556,17 +562,20 @@ function get_next_varsym(def: tabstractrecorddef; const SymList:TFPHashObjectLis
                          Local initialized vars are excluded because they are initialized
                          at function entry instead. }
                        if winlike and
-                          ((tcsym.owner.symtablelevel <= main_program_level) or
+                          ((tcsym.owner.symtablelevel<=main_program_level) or
                            (current_old_block_type=bt_const)) then
                          begin
+                           if ll.ofs<>0 then
+                             internalerror(2012051704);
                            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;
-                   list.concat(Tai_const.Create_sym(ll));
+                   list.concat(Tai_const.Create_sym_offset(ll.lab,ll.ofs));
                 end;
               else
                 internalerror(200107081);