From 8282d6e37a20cdaf405d198167d84e9a6e8158da Mon Sep 17 00:00:00 2001 From: Jonas Maebe Date: Sat, 19 May 2012 10:19:35 +0000 Subject: [PATCH] * 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 - --- compiler/asmutils.pas | 133 ++++++++++++++++++++++++++++++------------ compiler/cresstr.pas | 15 +++-- compiler/ncgcon.pas | 46 ++++++++++----- compiler/ngtcon.pas | 33 +++++++---- 4 files changed, 157 insertions(+), 70 deletions(-) diff --git a/compiler/asmutils.pas b/compiler/asmutils.pas index 570f598016..af3c0c713f 100644 --- a/compiler/asmutils.pas +++ b/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):TAsmLabel; - function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):TAsmLabel; + 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 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. diff --git a/compiler/cresstr.pas b/compiler/cresstr.pas index fb843102cb..0a1fc26d00 100644 --- a/compiler/cresstr.pas +++ b/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)); diff --git a/compiler/ncgcon.pas b/compiler/ncgcon.pas index 668a9001dc..d633ee4c15 100644 --- a/compiler/ncgcon.pas +++ b/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 diff --git a/compiler/ngtcon.pas b/compiler/ngtcon.pas index 9ecef25ce7..77180d9aa0 100644 --- a/compiler/ngtcon.pas +++ b/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);