diff options
author | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2012-04-11 18:02:08 +0000 |
---|---|---|
committer | jonas <jonas@3ad0048d-3df7-0310-abae-a5850022a9f2> | 2012-04-11 18:02:08 +0000 |
commit | 86637a61177afa91844d9fbd102b8bc5b127289d (patch) | |
tree | 6d5e331d84e31a02b679eb3b66e6126413e20fa3 | |
parent | 997c061ae1f2f0f0a56956208ec6418b35a047d6 (diff) | |
download | fpc-86637a61177afa91844d9fbd102b8bc5b127289d.tar.gz |
+ AIX assembler writer
o .short/.long/.llong are automatically aligned to 2/4/8 byte multiples
by the AIX assembler (and for compatibility reasons, also by the
GNU assembler when targeting AIX) -> change to .vbyte statements
o .ascii does not allow non-ASCII characters in the AIX assembler
-> change to .byte sequences like gcc on AIX
git-svn-id: http://svn.freepascal.org/svn/fpc/trunk@20803 3ad0048d-3df7-0310-abae-a5850022a9f2
-rw-r--r-- | compiler/aggas.pas | 263 | ||||
-rw-r--r-- | compiler/ppcgen/agppcgas.pas | 154 | ||||
-rw-r--r-- | compiler/systems.inc | 1 |
3 files changed, 363 insertions, 55 deletions
diff --git a/compiler/aggas.pas b/compiler/aggas.pas index cc3d43d641..2fc9dde536 100644 --- a/compiler/aggas.pas +++ b/compiler/aggas.pas @@ -48,8 +48,11 @@ interface function sectionattrs_coff(atype:TAsmSectiontype):string;virtual; procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder); procedure WriteExtraHeader;virtual; + procedure WriteExtraFooter;virtual; procedure WriteInstruction(hp: tai); procedure WriteWeakSymbolDef(s: tasmsymbol); virtual; + procedure WriteAixStringConst(hp: tai_string); + procedure WriteAixIntConst(hp: tai_const); public function MakeCmdLine: TCmdStr; override; procedure WriteTree(p:TAsmList);override; @@ -475,7 +478,9 @@ implementation system_i386_iphonesim, system_powerpc64_darwin, system_x86_64_darwin, - system_arm_darwin: + system_arm_darwin, + system_powerpc_aix, + system_powerpc64_aix: begin if (atype in [sec_stub,sec_objc_data,sec_objc_const,sec_data_coalesced]) then AsmWrite('.section '); @@ -586,7 +591,7 @@ implementation last_align:=alignment; if alignment>1 then begin - if not(target_info.system in systems_darwin) then + if not(target_info.system in (systems_darwin+systems_aix)) then begin AsmWrite(#9'.balign '+tostr(alignment)); if use_op then @@ -599,7 +604,7 @@ implementation end else begin - { darwin as only supports .align } + { darwin and aix as only support .align } if not ispowerof2(alignment,i) then internalerror(2003010305); AsmWrite(#9'.align '+tostr(i)); @@ -735,6 +740,28 @@ implementation asmln; end; end + else if target_info.system in systems_aix then + begin + if tai_datablock(hp).is_global then + begin + asmwrite(#9'.globl '); + asmwriteln(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); + asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); + asmwriteln(':'); + asmwrite(#9'.space '); + asmwriteln(tostr(tai_datablock(hp).size)); + if not(LastSecType in [sec_data,sec_none]) then + writesection(LastSecType,'',secorder_default); + end + else + begin + asmwrite(#9'.lcomm '); + asmwrite(ReplaceForbiddenAsmSymbolChars(tai_datablock(hp).sym.name)); + asmwrite(',_data.bss_[RW],'); + asmwrite(tostr(tai_datablock(hp).size)+','); + asmwriteln(tostr(last_align)); + end; + end else begin {$ifdef USE_COMM_IN_BSS} @@ -818,19 +845,24 @@ implementation begin if assigned(tai_const(hp).sym) then internalerror(200404292); - AsmWrite(ait_const2str[aitconst_32bit]); - if target_info.endian = endian_little then + if not(target_info.system in systems_aix) then begin - AsmWrite(tostr(longint(lo(tai_const(hp).value)))); - AsmWrite(','); - AsmWrite(tostr(longint(hi(tai_const(hp).value)))); + AsmWrite(ait_const2str[aitconst_32bit]); + if target_info.endian = endian_little then + begin + AsmWrite(tostr(longint(lo(tai_const(hp).value)))); + AsmWrite(','); + AsmWrite(tostr(longint(hi(tai_const(hp).value)))); + end + else + begin + AsmWrite(tostr(longint(hi(tai_const(hp).value)))); + AsmWrite(','); + AsmWrite(tostr(longint(lo(tai_const(hp).value)))); + end; end else - begin - AsmWrite(tostr(longint(hi(tai_const(hp).value)))); - AsmWrite(','); - AsmWrite(tostr(longint(lo(tai_const(hp).value)))); - end; + WriteAixIntConst(tai_const(hp)); AsmLn; end; {$endif cpu64bitaddr} @@ -849,7 +881,19 @@ implementation aitconst_darwin_dwarf_delta64, aitconst_half16bit: begin - if (target_info.system in systems_darwin) and + { the AIX assembler (and for compatibility, the GNU + assembler when targeting AIX) automatically aligns + .short/.long/.llong to a multiple of 2/4/8 bytes. We + don't want that, since this may be data inside a packed + record -> use .vbyte instead (byte stream of fixed + length) } + if (target_info.system in systems_aix) and + (constdef in [aitconst_128bit,aitconst_64bit,aitconst_32bit,aitconst_16bit]) and + not assigned(tai_const(hp).sym) then + begin + WriteAixIntConst(tai_const(hp)); + end + else if (target_info.system in systems_darwin) and (constdef in [aitconst_uleb128bit,aitconst_sleb128bit]) then begin AsmWrite(ait_const2str[aitconst_8bit]); @@ -1023,31 +1067,36 @@ implementation ait_string : begin pos:=0; - for i:=1 to tai_string(hp).len do - begin - if pos=0 then - begin - AsmWrite(#9'.ascii'#9'"'); - pos:=20; - end; - ch:=tai_string(hp).str[i-1]; - case ch of - #0, {This can't be done by range, because a bug in FPC} - #1..#31, - #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7); - '"' : s:='\"'; - '\' : s:='\\'; - else - s:=ch; - end; - AsmWrite(s); - inc(pos,length(s)); - if (pos>line_length) or (i=tai_string(hp).len) then - begin - AsmWriteLn('"'); - pos:=0; - end; - end; + if not(target_info.system in systems_aix) then + begin + for i:=1 to tai_string(hp).len do + begin + if pos=0 then + begin + AsmWrite(#9'.ascii'#9'"'); + pos:=20; + end; + ch:=tai_string(hp).str[i-1]; + case ch of + #0, {This can't be done by range, because a bug in FPC} + #1..#31, + #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7); + '"' : s:='\"'; + '\' : s:='\\'; + else + s:=ch; + end; + AsmWrite(s); + inc(pos,length(s)); + if (pos>line_length) or (i=tai_string(hp).len) then + begin + AsmWriteLn('"'); + pos:=0; + end; + end; + end + else + WriteAixStringConst(tai_string(hp)); end; ait_label : @@ -1112,6 +1161,30 @@ implementation { the dotted name is the name of the actual function entry } AsmWrite('.'); end + else if (target_info.system in systems_aix) and + (tai_symbol(hp).sym.typ = AT_FUNCTION) then + begin + if target_info.system=system_powerpc_aix then + begin + s:=#9'.long .'; + ch:='2'; + end + else + begin + s:=#9'.llong .'; + ch:='3'; + end; + AsmWriteLn(#9'.csect '+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+'[DS],'+ch); + AsmWriteLn(ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+':'); + AsmWriteln(s+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)+', TOC[tc0], 0'); + AsmWriteln(#9'.csect .text[PR]'); + if (tai_symbol(hp).is_global) then + AsmWriteLn('.globl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)) + else + AsmWriteLn('.lglobl .'+ReplaceForbiddenAsmSymbolChars(tai_symbol(hp).sym.name)); + { the dotted name is the name of the actual function entry } + AsmWrite('.'); + end else begin if (target_info.system <> system_arm_linux) then @@ -1275,6 +1348,11 @@ implementation end; + procedure TGNUAssembler.WriteExtraFooter; + begin + end; + + procedure TGNUAssembler.WriteInstruction(hp: tai); begin InstrWriter.WriteInstruction(hp); @@ -1287,6 +1365,113 @@ implementation end; + procedure TGNUAssembler.WriteAixStringConst(hp: tai_string); + type + tterminationkind = (term_none,term_string,term_nostring); + + var + i: longint; + pos: longint; + s: string; + ch: char; + instring: boolean; + + procedure newstatement(terminationkind: tterminationkind); + begin + case terminationkind of + term_none: ; + term_string: + AsmWriteLn('"'); + term_nostring: + AsmLn; + end; + AsmWrite(#9'.byte'#9); + pos:=20; + instring:=false; + end; + + begin + pos:=0; + for i:=1 to hp.len do + begin + if pos=0 then + newstatement(term_none); + ch:=hp.str[i-1]; + case ch of + #0..#31, + #127..#255 : + begin + if instring then + newstatement(term_string); + if pos=20 then + s:=tostr(ord(ch)) + else + s:=', '+tostr(ord(ch)) + end; + '"' : + if instring then + s:='""' + else + begin + if pos<>20 then + newstatement(term_nostring); + s:='"""'; + instring:=true; + end; + else + if not instring then + begin + if (pos<>20) then + newstatement(term_nostring); + s:='"'+ch; + instring:=true; + end + else + s:=ch; + end; + AsmWrite(s); + inc(pos,length(s)); + if (pos>line_length) or (i=tai_string(hp).len) then + begin + if instring then + AsmWriteLn('"') + else + AsmLn; + pos:=0; + end; + end; + end; + + + procedure TGNUAssembler.WriteAixIntConst(hp: tai_const); + var + pos, size: longint; + begin + { only big endian AIX supported for now } + if target_info.endian<>endian_big then + internalerror(2012010401); + { limitation: can only write 4 bytes at a time } + pos:=0; + size:=tai_const(hp).size; + while pos<(size-4) do + begin + AsmWrite(#9'.vbyte'#9'4, '); + AsmWriteln(tostr(longint(tai_const(hp).value shr ((size-pos-4)*8)))); + inc(pos,4); + end; + AsmWrite(#9'.vbyte'#9); + AsmWrite(tostr(size-pos)); + AsmWrite(', '); + case size-pos of + 1: AsmWrite(tostr(byte(tai_const(hp).value))); + 2: AsmWrite(tostr(word(tai_const(hp).value))); + 4: AsmWrite(tostr(longint(tai_const(hp).value))); + else + internalerror(2012010402); + end; + end; + + procedure TGNUAssembler.WriteAsmList; var n : string; diff --git a/compiler/ppcgen/agppcgas.pas b/compiler/ppcgen/agppcgas.pas index 5897489c69..1c1f58c483 100644 --- a/compiler/ppcgen/agppcgas.pas +++ b/compiler/ppcgen/agppcgas.pas @@ -52,6 +52,13 @@ unit agppcgas; function MakeCmdLine: TCmdStr; override; end; + TPPCAIXAssembler=class(TPPCGNUAssembler) + constructor create(smart: boolean); override; + procedure WriteExtraHeader; override; + procedure WriteExtraFooter; override; + function sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string; override; + end; + topstr = string[4]; function getreferencestring(var ref : treference) : string; @@ -91,22 +98,47 @@ unit agppcgas; if ((offset < -32768) or (offset > 32767)) and (refaddr = addr_no) then internalerror(2006052501); - if (refaddr = addr_no) then - s := '' - else - begin - if target_info.system in [system_powerpc_darwin,system_powerpc64_darwin] then - s := refaddr2str_darwin[refaddr] - else - s :=''; - s := s+'('; - if assigned(symbol) then - begin - s:=s+symbol.name; - if assigned(relsymbol) then - s:=s+'-'+relsymbol.name; - end; - end; + case refaddr of + addr_no: + s := ''; + addr_pic_no_got: + begin + { used for TOC-based loads } + if (base<>NR_RTOC) or + (index<>NR_NO) or + (offset<>0) or + not assigned(symbol) then + internalerror(2011122701); + if target_asm.dollarsign<>'$' then + getreferencestring:=ReplaceForbiddenAsmSymbolChars(symbol.name)+'('+gas_regname(NR_RTOC)+')' + else + getreferencestring:=symbol.name+'('+gas_regname(NR_RTOC)+')'; + exit; + end + else + begin + if target_info.system in [system_powerpc_darwin,system_powerpc64_darwin] then + s := refaddr2str_darwin[refaddr] + else + s :=''; + s := s+'('; + if assigned(symbol) then + begin + if target_asm.dollarsign<>'$' then + begin + s:=s+ReplaceForbiddenAsmSymbolChars(symbol.name); + if assigned(relsymbol) then + s:=s+'-'+ReplaceForbiddenAsmSymbolChars(relsymbol.name) + end + else + begin + s:=s+symbol.name; + if assigned(relsymbol) then + s:=s+'-'+relsymbol.name; + end; + end; + end; + end; if offset<0 then s:=s+tostr(offset) else @@ -414,7 +446,77 @@ unit agppcgas; end; +{****************************************************************************} +{ AIX PPC Assembler writer } +{****************************************************************************} + + constructor TPPCAIXAssembler.create(smart: boolean); + begin + inherited create(smart); + InstrWriter := TPPCInstrWriter.create(self); + end; + + + procedure TPPCAIXAssembler.WriteExtraHeader; + var + i: longint; + begin + inherited WriteExtraHeader; + { AIX assembler notation for .quad is .llong, let assembler itself + perform the substitution; the aix assembler uses .quad for defining + 128 bit floating point numbers, but + a) we don't support those yet + b) once we support them, we'll encode them byte per byte like other + floating point numbers } + AsmWriteln(#9'.set'#9'.quad,.llong'); + { map cr registers to plain numbers } + for i:=0 to 7 do + AsmWriteln(#9'.set'#9'cr'+tostr(i)+','+tostr(i)); + { make sure we always have a code and toc section, the linker expects + that } + AsmWriteln(#9'.csect .text[PR]'); + AsmWriteln(#9'.toc'); + end; + + + procedure TPPCAIXAssembler.WriteExtraFooter; + begin + inherited WriteExtraFooter; + { link between data and text section } + AsmWriteln('_section_.text:'); + AsmWriteln(#9'.csect .data[RW],4'); +{$ifdef cpu64bitaddr} + AsmWrite(#9'.llong _section_.text') +{$else cpu64bitaddr} + AsmWrite(#9'.long _section_.text') +{$endif cpu64bitaddr} + end; + + function TPPCAIXAssembler.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string; + begin + case atype of + sec_code: + result:='.csect .text[PR]'; + sec_data, + sec_rodata, + { don't use .bss[BS], causes relocation problems } + sec_bss: + result:='.csect .data[RW]'; + sec_rodata_norel: + result:='.csect .text[RO]'; + sec_fpc: + result:='.csect .fpc[RO]'; + sec_toc: + result:='.toc'; + { automatically placed in the right section } + sec_stab, + sec_stabstr: + result:=''; + else + internalerror(2011122601); + end; + end; {***************************************************************************** @@ -456,7 +558,27 @@ unit agppcgas; ); + as_ppc_aix_powerpc_info : tasminfo = + ( + id : as_powerpc_xcoff; + + idtxt : 'AS-AIX'; + asmbin : 'as'; + { -u: allow using symbols before they are defined (when using native + AIX assembler, ignore by GNU assembler) + -mpwr5: we actually support Power3 and higher, but the AIX assembler + has no parameter to select that one (only -mpwr3 and -mpwr5) } + asmcmd : '-u -o $OBJ $ASM -mpwr5'; + supported_targets : [system_powerpc_aix,system_powerpc64_aix]; + flags : [af_needar,af_smartlink_sections,af_stabs_use_function_absolute_addresses]; + labelprefix : 'L'; + comment : '# '; + dollarsign : '.' + ); + + begin RegisterAssembler(as_ppc_gas_info,TPPCGNUAssembler); RegisterAssembler(as_ppc_gas_darwin_powerpc_info,TPPCAppleGNUAssembler); + RegisterAssembler(as_ppc_aix_powerpc_info,TPPCAIXAssembler); end. diff --git a/compiler/systems.inc b/compiler/systems.inc index a352c70985..c05ca5ab95 100644 --- a/compiler/systems.inc +++ b/compiler/systems.inc @@ -184,6 +184,7 @@ ,as_i386_nasmhaiku ,as_powerpc_vasm ,as_i386_nlmcoff + ,as_powerpc_xcoff ); tar = (ar_none |