* 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 -
This commit is contained in:
Jonas Maebe 2012-05-19 10:19:35 +00:00
parent 7ae1db2e01
commit 8282d6e37a
4 changed files with 157 additions and 70 deletions

View File

@ -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):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):TAsmLabel; function emit_unicodestring_const(list:TAsmList;data:Pointer;encoding:tstringencoding;Winlike:Boolean):tasmlabofs;
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))); new_section(list,sec_rodata,result.lab.name,const_align(sizeof(pint)));
referencelab := nil; { 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 list.concat(tai_label.create(result.lab));
current_asmdata.getdatalabel(referencelab);
list.concat(tai_label.create(referencelab));
end;
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 } inc(result.ofs,sizeof(pint));
if target_info.system in systems_darwin then if not(target_info.system in systems_darwin) then
list.concat(tai_directive.create(asd_reference,result.name)); begin
list.concat(tai_label.create(result)); { results in slightly more efficient code }
{ and vice versa } list.concat(tai_label.create(result.lab));
if target_info.system in systems_darwin then result.ofs:=0;
list.concat(tai_directive.create(asd_reference,referencelab.name)); 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); current_asmdata.getdatalabel(result.lab);
new_section(list,sec_rodata,result.name,const_align(sizeof(pint))); result.ofs:=0;
referencelab := nil; new_section(list,sec_rodata,result.lab.name,const_align(sizeof(pint)));
if target_info.system in systems_darwin then
begin
current_asmdata.getdatalabel(referencelab);
list.concat(tai_label.create(referencelab));
end;
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.

View File

@ -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_offset(namelab.lab,namelab.ofs));
current_asmdata.asmlists[al_resourcestrings].concat(tai_const.create_sym(valuelab)); 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(valuelab)); 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));

View File

@ -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], begin
value_str, lastlabel := emit_unicodestring_const(current_asmdata.AsmLists[al_typedconsts],
tstringdef(resultdef).encoding, value_str,
(cst_type=cst_widestring) and (tf_winlikewidestring in target_info.flags)); 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; lab_str:=lastlabel.lab;
entry^.Data:=lastlabel; 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

View File

@ -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); ll:=emit_ansistring_const(current_asmdata.asmlists[al_const],strval,strlength,def.encoding);
list.concat(Tai_const.Create_sym(ll)); 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); winlike:=(def.stringtype=st_widestring) and (tf_winlikewidestring in target_info.flags);
ll := emit_unicodestring_const(current_asmdata.asmlists[al_const], 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; ll.lab:=nil;
Include(tcsym.varoptions, vo_force_finalize); 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);