+ AIX symbol handling: load symbol address from the TOC

* fixed code dealing with symbol+offsets on 64 bit platforms in
    case of offsets > 32 bit (and to use smallint() typecasts
    instead of lo(), since the return value of lo() depends on
    the type passed in)

git-svn-id: trunk@20793 -
This commit is contained in:
Jonas Maebe 2012-04-11 18:00:48 +00:00
parent 481b3d99a9
commit 509df28361

View File

@ -61,9 +61,13 @@ unit cgppc;
procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);override;
procedure g_maybe_got_init(list: TAsmList); override;
function g_indirect_sym_load(list:TAsmList;const symname: string; const flags: tindsymflags): tregister; override;
{ Transform unsupported methods into Internal errors }
procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; size: TCGSize; src, dst: TRegister); override;
procedure g_stackpointer_alloc(list : TAsmList;localsize : longint);override;
function get_aix_toc_sym(const symname: string; const flags: tindsymflags):tasmsymbol;
protected
function get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
procedure a_load_subsetref_regs_noindex(list: TAsmList; subsetsize: tcgsize; loadbitsize: byte; const sref: tsubsetreference; valuereg, extra_value_reg: tregister); override;
@ -89,7 +93,7 @@ unit cgppc;
function save_lr_in_prologue: boolean;
function load_got_symbol(list : TAsmList; symbol : string) : tregister;
function load_got_symbol(list : TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
end;
const
@ -251,6 +255,18 @@ unit cgppc;
end;
function tcgppcgen.g_indirect_sym_load(list: TAsmList; const symname: string; const flags: tindsymflags): tregister;
begin
case target_info.system of
system_powerpc_aix,
system_powerpc64_aix:
result:=load_got_symbol(list,symname,flags);
else
result:=inherited;
end;
end;
function tcgppcgen.get_darwin_call_stub(const s: string; weak: boolean): tasmsymbol;
var
stubname: string;
@ -351,13 +367,8 @@ unit cgppc;
tmpref.base := NR_RTOC;
list.concat(taicpu.op_reg_ref(A_LWZ,r,tmpref));
if ref2.offset <> 0 then
begin
reference_reset(tmpref,ref2.alignment);
tmpref.offset := ref2.offset;
tmpref.base:= r;
list.concat(taicpu.op_reg_ref(A_LA,r,tmpref));
end;
if ref2.offset<>0 then
a_op_const_reg(list,OP_ADD,OS_ADDR,ref2.offset,r);
end;
if ref2.base <> NR_NO then
@ -686,14 +697,14 @@ unit cgppc;
href.offset := smallint(href.offset and $ffff);
end;
a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,NR_R11);
if (target_info.system = system_powerpc64_linux) then
if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
begin
reference_reset_base(href, NR_R11, 0, sizeof(pint));
a_load_ref_reg(list, OS_ADDR, OS_ADDR, href, NR_R11);
end;
list.concat(taicpu.op_reg(A_MTCTR,NR_R11));
list.concat(taicpu.op_none(A_BCTR));
if (target_info.system = system_powerpc64_linux) then
if (target_info.system in ([system_powerpc64_linux]+systems_aix)) then
list.concat(taicpu.op_none(A_NOP));
end;
@ -747,24 +758,25 @@ unit cgppc;
end;
function tcgppcgen.load_got_symbol(list: TAsmList; symbol : string) : tregister;
function tcgppcgen.load_got_symbol(list: TAsmList; const symbol : string; const flags: tindsymflags) : tregister;
var
l: tasmsymbol;
ref: treference;
begin
if (target_info.system <> system_powerpc64_linux) then
if target_info.system=system_powerpc64_linux then
l:=current_asmdata.getasmsymbol(symbol)
else if target_info.system in systems_aix then
l:=get_aix_toc_sym(symbol,flags)
else
internalerror(2007102010);
l:=current_asmdata.getasmsymbol(symbol);
reference_reset_symbol(ref,l,0,sizeof(pint));
ref.base := NR_R2;
ref.refaddr := addr_pic;
result := rg[R_INTREGISTER].getregister(list, R_SUBWHOLE);
{$IFDEF EXTDEBUG}
list.concat(tai_comment.create(strpnew('loading got reference for ' + symbol)));
{$ENDIF EXTDEBUG}
// cg.a_load_ref_reg(list,OS_ADDR,OS_ADDR,ref,result);
ref.base:=NR_RTOC;
if target_info.system in systems_aix then
ref.refaddr:=addr_pic_no_got
else
ref.refaddr:=addr_pic;
result := getaddressregister(list);
{$ifdef cpu64bitaddr}
list.concat(taicpu.op_reg_ref(A_LD, result, ref));
{$else cpu64bitaddr}
@ -773,6 +785,34 @@ unit cgppc;
end;
function tcgppcgen.get_aix_toc_sym(const symname: string; const flags: tindsymflags): tasmsymbol;
var
nlsymname: string;
newsymname: ansistring;
begin
{ all global symbol accesses always must be done via the TOC }
nlsymname:='LC..'+symname;
result:=current_asmdata.getasmsymbol(nlsymname);
if not assigned(result) then
begin
new_section(current_asmdata.AsmLists[al_picdata],sec_toc,'',sizeof(pint));
result:=current_asmdata.DefineAsmSymbol(nlsymname,AB_LOCAL,AT_DATA);
current_asmdata.asmlists[al_picdata].concat(tai_symbol.create(result,0));
{ do not assign the result of these statements to result: the access
must be done via the LC..symname symbol; these are just to define
the symbol that's being accessed as either weak or not }
if not(is_weak in flags) then
current_asmdata.RefAsmSymbol(symname)
else if is_data in flags then
current_asmdata.WeakRefAsmSymbol(symname)
else
current_asmdata.WeakRefAsmSymbol('.'+symname);
newsymname:=ReplaceForbiddenChars(symname);
current_asmdata.asmlists[al_picdata].concat(tai_directive.Create(asd_toc_entry,newsymname+'[TC],'+newsymname));
end;
end;
function tcgppcgen.fixref(list: TAsmList; var ref: treference): boolean;
var
tmpreg: tregister;
@ -780,7 +820,7 @@ unit cgppc;
result := false;
{ Avoid recursion. }
if (ref.refaddr = addr_pic) then
if (ref.refaddr in [addr_pic,addr_pic_no_got]) then
exit;
{$IFDEF EXTDEBUG}
@ -796,7 +836,7 @@ unit cgppc;
((cs_create_pic in current_settings.moduleswitches) and
(ref.symbol.bind in [AB_COMMON,AB_GLOBAL,AB_PRIVATE_EXTERN])) then
begin
tmpreg := g_indirect_sym_load(list,ref.symbol.name,ref.symbol.bind=AB_WEAK_EXTERNAL);
tmpreg := g_indirect_sym_load(list,ref.symbol.name,asmsym2indsymflags(ref.symbol));
ref.symbol:=nil;
end
else
@ -819,11 +859,12 @@ unit cgppc;
end;
{ if we have to create PIC, add the symbol to the TOC/GOT }
if (target_info.system = system_powerpc64_linux) and
(cs_create_pic in current_settings.moduleswitches) and
if (((target_info.system = system_powerpc64_linux) and
(cs_create_pic in current_settings.moduleswitches)) or
(target_info.system in systems_aix)) and
(assigned(ref.symbol)) then
begin
tmpreg := load_got_symbol(list, ref.symbol.name);
tmpreg := load_got_symbol(list, ref.symbol.name, asmsym2indsymflags(ref.symbol));
if (ref.base = NR_NO) then
ref.base := tmpreg
else if (ref.index = NR_NO) then
@ -871,6 +912,9 @@ unit cgppc;
var
tmpreg: tregister;
{$ifdef cpu64bitaddr}
tmpreg2: tregister;
{$endif cpu64bitaddr}
tmpref: treference;
largeOffset: Boolean;
@ -878,38 +922,57 @@ unit cgppc;
tmpreg := NR_NO;
largeOffset:= hasLargeOffset(ref);
if target_info.system = system_powerpc_macos then
if target_info.system in ([system_powerpc_macos]+systems_aix) then
begin
if assigned(ref.symbol) then
if assigned(ref.symbol) and
(ref.refaddr<>addr_pic_no_got) then
begin {Load symbol's value}
tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
reference_reset(tmpref,sizeof(pint));
tmpref.symbol := ref.symbol;
tmpref.base := NR_RTOC;
tmpref.refaddr := addr_pic_no_got;
if macos_direct_globals then
list.concat(taicpu.op_reg_ref(A_LA,tmpreg,tmpref))
else
{$ifdef cpu64bitaddr}
list.concat(taicpu.op_reg_ref(A_LD,tmpreg,tmpref));
{$else cpu64bitaddr}
list.concat(taicpu.op_reg_ref(A_LWZ,tmpreg,tmpref));
{$endif cpu64bitaddr}
end;
if largeOffset then
begin {Add hi part of offset}
reference_reset(tmpref,ref.alignment);
if Smallint(Lo(ref.offset)) < 0 then
tmpref.offset := Hi(ref.offset) + 1 {Compensate when lo part is negative}
else
tmpref.offset := Hi(ref.offset);
{$ifdef cpu64bitaddr}
if (ref.offset < low(longint)) or
(ref.offset > high(longint)) then
begin
{ load upper 32 bits of the offset, adjusted for adding
the lower 32 bits later }
tmpreg2:=getintregister(list,OS_ADDR);
a_load_const_reg(list,OS_ADDR,(ref.offset and $ffffffff00000000) + ord(longint(ref.offset)<0),tmpreg2);
if tmpreg=NR_NO then
tmpreg:=tmpreg2
else
a_op_reg_reg(list,OP_ADD,OS_ADDR,tmpreg2,tmpreg);
ref.offset:=longint(ref.offset);
end;
{$endif cpu64bitaddr}
{Compensate when lo part is negative}
tmpref.offset := Smallint(ref.offset >> 16) + ord(Smallint(ref.offset) < 0);
if (tmpreg <> NR_NO) then
list.concat(taicpu.op_reg_reg_ref(A_ADDIS,tmpreg, tmpreg,tmpref))
list.concat(taicpu.op_reg_reg_const(A_ADDIS,tmpreg, tmpreg,tmpref.offset))
else
begin
tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
list.concat(taicpu.op_reg_ref(A_LIS,tmpreg,tmpref));
tmpreg := getintregister(list,OS_ADDR);
list.concat(taicpu.op_reg_const(A_LIS,tmpreg,tmpref.offset));
end;
end;
@ -924,7 +987,7 @@ unit cgppc;
ref.symbol:= nil;
ref.base:= tmpreg;
if largeOffset then
ref.offset := Smallint(Lo(ref.offset));
ref.offset := Smallint(ref.offset);
list.concat(taicpu.op_reg_ref(op,reg,ref));
//list.concat(tai_comment.create(strpnew('*** a_load_store indirect global')));
@ -937,6 +1000,7 @@ unit cgppc;
if assigned(ref.symbol) or
largeOffset then
begin
// TODO: offsets > 32 bit
tmpreg := rg[R_INTREGISTER].getregister(list,R_SUBWHOLE);
reference_reset(tmpref,ref.alignment);
tmpref.symbol := ref.symbol;