mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-16 04:50:51 +01:00
+ 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:
parent
481b3d99a9
commit
509df28361
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user