diff options
author | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2015-02-23 22:53:43 +0000 |
---|---|---|
committer | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2015-02-23 22:53:43 +0000 |
commit | 1afa31fdc5ce2e47324778c31646ebb689fcede2 (patch) | |
tree | 6723d7e6b769ca72cfb49f9aec1cd0fced3fedc6 /compiler | |
parent | c201ba6bc2eccb124235789286b2d96b266b2f5c (diff) | |
download | fpc-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.pas | 10 | ||||
-rw-r--r-- | compiler/aarch64/agcpugas.pas | 135 | ||||
-rw-r--r-- | compiler/aarch64/cgcpu.pas | 34 | ||||
-rw-r--r-- | compiler/aarch64/racpugas.pas | 9 | ||||
-rw-r--r-- | compiler/cgbase.pas | 2 |
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} |