* 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
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.

View File

@ -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));

View File

@ -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

View File

@ -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);