summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
authorjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2015-02-23 22:53:43 +0000
committerjonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2>2015-02-23 22:53:43 +0000
commit1afa31fdc5ce2e47324778c31646ebb689fcede2 (patch)
tree6723d7e6b769ca72cfb49f9aec1cd0fced3fedc6 /compiler
parentc201ba6bc2eccb124235789286b2d96b266b2f5c (diff)
downloadfpc-1afa31fdc5ce2e47324778c31646ebb689fcede2.tar.gz
+ support for @page and @pageoffs addressing on AArch64: these are PIC
references that directly take the address of a symbol, rather than of its GOT entry o use these addressing modes to access local symbols git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@29932 3ad0048d-3df7-0310-abae-a5850022a9f2
Diffstat (limited to 'compiler')
-rw-r--r--compiler/aarch64/aasmcpu.pas10
-rw-r--r--compiler/aarch64/agcpugas.pas135
-rw-r--r--compiler/aarch64/cgcpu.pas34
-rw-r--r--compiler/aarch64/racpugas.pas9
-rw-r--r--compiler/cgbase.pas2
5 files changed, 115 insertions, 75 deletions
diff --git a/compiler/aarch64/aasmcpu.pas b/compiler/aarch64/aasmcpu.pas
index bef039dcd8..a8a910d20a 100644
--- a/compiler/aarch64/aasmcpu.pas
+++ b/compiler/aarch64/aasmcpu.pas
@@ -569,7 +569,7 @@ implementation
begin
result:=sr_complex;
if not assigned(ref.symboldata) and
- not(ref.refaddr in [addr_pic,addr_gotpageoffset,addr_gotpage]) then
+ not(ref.refaddr in [addr_gotpageoffset,addr_gotpage,addr_pageoffset,addr_page]) then
exit;
{ can't use pre-/post-indexed mode here (makes no sense either) }
if ref.addressmode<>AM_OFFSET then
@@ -580,9 +580,9 @@ implementation
not(oppostfix in [PF_NONE,PF_W,PF_SW]) or
not assigned(ref.symbol)) then
exit;
- { if this is a got offset load, we must have a base register and a
+ { if this is a (got) page offset load, we must have a base register and a
symbol }
- if (ref.refaddr=addr_gotpageoffset) and
+ if (ref.refaddr in [addr_gotpageoffset,addr_pageoffset]) and
(not assigned(ref.symbol) or
(ref.base=NR_NO) or
(ref.index<>NR_NO) or
@@ -594,7 +594,7 @@ implementation
{ cannot have base or index register (we generate these kind of
references internally, they should never end up here with an
extra base or offset) }
- if (ref.refaddr in [addr_gotpage,addr_pic]) and
+ if (ref.refaddr in [addr_gotpage,addr_page]) and
(ref.base<>NR_NO) or
(ref.index<>NR_NO) then
begin
@@ -647,7 +647,7 @@ implementation
end;
{ any other reference cannot be gotpage/gotpageoffset/pic }
- if ref.refaddr in [addr_gotpage,addr_gotpageoffset,addr_pic] then
+ if ref.refaddr in [addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset,addr_pic] then
exit;
{ base & index:
diff --git a/compiler/aarch64/agcpugas.pas b/compiler/aarch64/agcpugas.pas
index c858a12404..8e2ab8c82e 100644
--- a/compiler/aarch64/agcpugas.pas
+++ b/compiler/aarch64/agcpugas.pas
@@ -83,76 +83,85 @@ unit agcpugas;
{****************************************************************************}
function getreferencestring(var ref : treference) : string;
+ const
+ darwin_addrpage2str: array[addr_page..addr_gotpageoffset] of string[11] =
+ ('@PAGE','@PAGEOFF','@GOTPAGE','@GOTPAGEOFF');
begin
- case ref.refaddr of
- addr_gotpage:
- begin
- if not assigned(ref.symbol) or
- (ref.base<>NR_NO) or
- (ref.index<>NR_NO) or
- (ref.shiftmode<>SM_None) or
- (ref.offset<>0) then
- internalerror(2014121501);
- if target_asm.id=as_darwin then
- result:=ref.symbol.name+'@GOTPAGE'
- else
- { todo }
- internalerror(2014121502);
- end
- else
- begin
- if ref.base=NR_NO then
- internalerror(2014121503);
- result:='['+gas_regname(ref.base);
- if ref.addressmode=AM_POSTINDEXED then
- result:=result+']';
- if ref.index<>NR_NO then
+ if ref.base=NR_NO then
+ begin
+ case ref.refaddr of
+ addr_gotpage,
+ addr_page,
+ addr_gotpageoffset,
+ addr_pageoffset:
begin
- if (ref.offset<>0) or
- assigned(ref.symbol) then
- internalerror(2014121504);
- result:=result+', '+gas_regname(ref.index);
- case ref.shiftmode of
- SM_None: ;
- SM_LSL,
- SM_UXTB, SM_UXTH, SM_UXTW, SM_UXTX,
- SM_SXTB, SM_SXTH, SM_SXTW, SM_SXTX:
- result:=result+', lsl #'+tostr(ref.shiftimm);
- else
- internalerror(2014121505);
- end;
+ if not assigned(ref.symbol) or
+ (ref.base<>NR_NO) or
+ (ref.index<>NR_NO) or
+ (ref.shiftmode<>SM_None) or
+ (ref.offset<>0) then
+ internalerror(2014121501);
+ if target_asm.id=as_darwin then
+ result:=ref.symbol.name+darwin_addrpage2str[ref.refaddr]
+ else
+ { todo }
+ internalerror(2014121502);
end
- else
- begin
- if assigned(ref.symbol) then
- begin
- case ref.refaddr of
- addr_gotpageoffset:
- begin
- if target_asm.id=as_darwin then
- result:=result+', '+ref.symbol.name+'@GOTPAGEOFF'
- else
- result:=result+', #:lo12:'+ref.symbol.name;
- end
- else
- { todo: not yet generated/don't know syntax }
- internalerror(2014121506);
- end;
- end
+ end
+ end
+ else
+ begin
+ result:='['+gas_regname(ref.base);
+ if ref.addressmode=AM_POSTINDEXED then
+ result:=result+']';
+ if ref.index<>NR_NO then
+ begin
+ if (ref.offset<>0) or
+ assigned(ref.symbol) then
+ internalerror(2014121504);
+ result:=result+', '+gas_regname(ref.index);
+ case ref.shiftmode of
+ SM_None: ;
+ SM_LSL,
+ SM_UXTB, SM_UXTH, SM_UXTW, SM_UXTX,
+ SM_SXTB, SM_SXTH, SM_SXTW, SM_SXTX:
+ result:=result+', lsl #'+tostr(ref.shiftimm);
else
- begin
- if ref.refaddr<>addr_no then
+ internalerror(2014121505);
+ end;
+ end
+ else
+ begin
+ if assigned(ref.symbol) then
+ begin
+ case ref.refaddr of
+ addr_gotpageoffset,
+ addr_pageoffset:
+ begin
+ if target_asm.id=as_darwin then
+ result:=result+', '+ref.symbol.name+darwin_addrpage2str[ref.refaddr]
+ else
+ { todo }
+ internalerror(2014122510);
+ end
+ else
+ { todo: not yet generated/don't know syntax }
internalerror(2014121506);
- if (ref.offset<>0) then
- result:=result+', #'+tostr(ref.offset);
end;
- end;
- case ref.addressmode of
- AM_OFFSET:
- result:=result+']';
- AM_PREINDEXED:
- result:=result+']!';
+ end
+ else
+ begin
+ if ref.refaddr<>addr_no then
+ internalerror(2014121506);
+ if (ref.offset<>0) then
+ result:=result+', #'+tostr(ref.offset);
+ end;
end;
+ case ref.addressmode of
+ AM_OFFSET:
+ result:=result+']';
+ AM_PREINDEXED:
+ result:=result+']!';
end;
end;
end;
diff --git a/compiler/aarch64/cgcpu.pas b/compiler/aarch64/cgcpu.pas
index 11236d303e..5b58749ac7 100644
--- a/compiler/aarch64/cgcpu.pas
+++ b/compiler/aarch64/cgcpu.pas
@@ -154,7 +154,7 @@ implementation
begin
{ internal "load symbol" instructions should already be valid }
if assigned(ref.symboldata) or
- (ref.refaddr in [addr_pic,addr_gotpage,addr_gotpageoffset]) then
+ (ref.refaddr in [addr_pic,addr_gotpage,addr_gotpageoffset,addr_page,addr_pageoffset]) then
internalerror(2014110802);
{ no relative symbol support (needed) yet }
if assigned(ref.relsymbol) then
@@ -171,17 +171,37 @@ implementation
(ref.base=preferred_newbasereg) or
(ref.index=preferred_newbasereg) then
preferred_newbasereg:=getaddressregister(list);
- { load the GOT page }
+ { load the (GOT) page }
reference_reset_symbol(href,ref.symbol,0,8);
- href.refaddr:=addr_gotpage;
+ if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and
+ (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or
+ ((ref.symbol.typ=AT_DATA) and
+ (ref.symbol.bind=AB_LOCAL)) then
+ href.refaddr:=addr_page
+ else
+ href.refaddr:=addr_gotpage;
list.concat(taicpu.op_reg_ref(A_ADRP,preferred_newbasereg,href));
{ load the GOT entry (= address of the variable) }
reference_reset_base(href,preferred_newbasereg,0,sizeof(pint));
href.symbol:=ref.symbol;
- href.refaddr:=addr_gotpageoffset;
- { use a_load_ref_reg() rather than directly encoding the LDR,
- so that we'll check the validity of the reference }
- a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,preferred_newbasereg);
+ { code symbols defined in the current compilation unit do not
+ have to be accessed via the GOT }
+ if ((ref.symbol.typ in [AT_FUNCTION,AT_LABEL]) and
+ (ref.symbol.bind in [AB_LOCAL,AB_GLOBAL])) or
+ ((ref.symbol.typ=AT_DATA) and
+ (ref.symbol.bind=AB_LOCAL)) then
+ begin
+ href.base:=NR_NO;
+ href.refaddr:=addr_pageoffset;
+ list.concat(taicpu.op_reg_reg_ref(A_ADD,preferred_newbasereg,preferred_newbasereg,href));
+ end
+ else
+ begin
+ href.refaddr:=addr_gotpageoffset;
+ { use a_load_ref_reg() rather than directly encoding the LDR,
+ so that we'll check the validity of the reference }
+ a_load_ref_reg(list,OS_ADDR,OS_ADDR,href,preferred_newbasereg);
+ end;
{ set as new base register }
if ref.base=NR_NO then
ref.base:=preferred_newbasereg
diff --git a/compiler/aarch64/racpugas.pas b/compiler/aarch64/racpugas.pas
index 01870f4086..717b96f28d 100644
--- a/compiler/aarch64/racpugas.pas
+++ b/compiler/aarch64/racpugas.pas
@@ -308,6 +308,11 @@ Unit racpugas;
consume(actasmtoken);
oper.opr.ref.refaddr:=addr_gotpageoffset;
end
+ else if actasmpattern='PAGEOFF' then
+ begin
+ consume(actasmtoken);
+ oper.opr.ref.refaddr:=addr_pageoffset;
+ end
else
begin
do_error;
@@ -532,6 +537,10 @@ Unit racpugas;
oper.opr.ref.refaddr:=addr_gotpage
else if actasmpattern='GOTPAGEOFF' then
oper.opr.ref.refaddr:=addr_gotpageoffset
+ else if actasmpattern='PAGE' then
+ oper.opr.ref.refaddr:=addr_page
+ else if actasmpattern='PAGEOFF' then
+ oper.opr.ref.refaddr:=addr_pageoffset
else
Message(asmr_e_expr_illegal);
consume(actasmtoken);
diff --git a/compiler/cgbase.pas b/compiler/cgbase.pas
index 065c00e935..dff6e84ea7 100644
--- a/compiler/cgbase.pas
+++ b/compiler/cgbase.pas
@@ -102,6 +102,8 @@ interface
,addr_seg // used for getting the segment of an object, e.g. 'mov ax, SEG symbol'
{$ENDIF}
{$IFDEF AARCH64}
+ ,addr_page
+ ,addr_pageoffset
,addr_gotpage
,addr_gotpageoffset
{$ENDIF AARCH64}