+ 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: trunk@20803 -
This commit is contained in:
Jonas Maebe 2012-04-11 18:02:08 +00:00
parent 260958eb45
commit 273b90fc37
3 changed files with 363 additions and 55 deletions

View File

@ -48,8 +48,11 @@ interface
function sectionattrs_coff(atype:TAsmSectiontype):string;virtual; function sectionattrs_coff(atype:TAsmSectiontype):string;virtual;
procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder); procedure WriteSection(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder);
procedure WriteExtraHeader;virtual; procedure WriteExtraHeader;virtual;
procedure WriteExtraFooter;virtual;
procedure WriteInstruction(hp: tai); procedure WriteInstruction(hp: tai);
procedure WriteWeakSymbolDef(s: tasmsymbol); virtual; procedure WriteWeakSymbolDef(s: tasmsymbol); virtual;
procedure WriteAixStringConst(hp: tai_string);
procedure WriteAixIntConst(hp: tai_const);
public public
function MakeCmdLine: TCmdStr; override; function MakeCmdLine: TCmdStr; override;
procedure WriteTree(p:TAsmList);override; procedure WriteTree(p:TAsmList);override;
@ -475,7 +478,9 @@ implementation
system_i386_iphonesim, system_i386_iphonesim,
system_powerpc64_darwin, system_powerpc64_darwin,
system_x86_64_darwin, system_x86_64_darwin,
system_arm_darwin: system_arm_darwin,
system_powerpc_aix,
system_powerpc64_aix:
begin begin
if (atype in [sec_stub,sec_objc_data,sec_objc_const,sec_data_coalesced]) then if (atype in [sec_stub,sec_objc_data,sec_objc_const,sec_data_coalesced]) then
AsmWrite('.section '); AsmWrite('.section ');
@ -586,7 +591,7 @@ implementation
last_align:=alignment; last_align:=alignment;
if alignment>1 then if alignment>1 then
begin begin
if not(target_info.system in systems_darwin) then if not(target_info.system in (systems_darwin+systems_aix)) then
begin begin
AsmWrite(#9'.balign '+tostr(alignment)); AsmWrite(#9'.balign '+tostr(alignment));
if use_op then if use_op then
@ -599,7 +604,7 @@ implementation
end end
else else
begin begin
{ darwin as only supports .align } { darwin and aix as only support .align }
if not ispowerof2(alignment,i) then if not ispowerof2(alignment,i) then
internalerror(2003010305); internalerror(2003010305);
AsmWrite(#9'.align '+tostr(i)); AsmWrite(#9'.align '+tostr(i));
@ -735,6 +740,28 @@ implementation
asmln; asmln;
end; end;
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 else
begin begin
{$ifdef USE_COMM_IN_BSS} {$ifdef USE_COMM_IN_BSS}
@ -818,19 +845,24 @@ implementation
begin begin
if assigned(tai_const(hp).sym) then if assigned(tai_const(hp).sym) then
internalerror(200404292); internalerror(200404292);
AsmWrite(ait_const2str[aitconst_32bit]); if not(target_info.system in systems_aix) then
if target_info.endian = endian_little then
begin begin
AsmWrite(tostr(longint(lo(tai_const(hp).value)))); AsmWrite(ait_const2str[aitconst_32bit]);
AsmWrite(','); if target_info.endian = endian_little then
AsmWrite(tostr(longint(hi(tai_const(hp).value)))); 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 end
else else
begin WriteAixIntConst(tai_const(hp));
AsmWrite(tostr(longint(hi(tai_const(hp).value))));
AsmWrite(',');
AsmWrite(tostr(longint(lo(tai_const(hp).value))));
end;
AsmLn; AsmLn;
end; end;
{$endif cpu64bitaddr} {$endif cpu64bitaddr}
@ -849,7 +881,19 @@ implementation
aitconst_darwin_dwarf_delta64, aitconst_darwin_dwarf_delta64,
aitconst_half16bit: aitconst_half16bit:
begin 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 (constdef in [aitconst_uleb128bit,aitconst_sleb128bit]) then
begin begin
AsmWrite(ait_const2str[aitconst_8bit]); AsmWrite(ait_const2str[aitconst_8bit]);
@ -1023,31 +1067,36 @@ implementation
ait_string : ait_string :
begin begin
pos:=0; pos:=0;
for i:=1 to tai_string(hp).len do if not(target_info.system in systems_aix) then
begin begin
if pos=0 then for i:=1 to tai_string(hp).len do
begin begin
AsmWrite(#9'.ascii'#9'"'); if pos=0 then
pos:=20; begin
end; AsmWrite(#9'.ascii'#9'"');
ch:=tai_string(hp).str[i-1]; pos:=20;
case ch of end;
#0, {This can't be done by range, because a bug in FPC} ch:=tai_string(hp).str[i-1];
#1..#31, case ch of
#128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7); #0, {This can't be done by range, because a bug in FPC}
'"' : s:='\"'; #1..#31,
'\' : s:='\\'; #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
else '"' : s:='\"';
s:=ch; '\' : s:='\\';
end; else
AsmWrite(s); s:=ch;
inc(pos,length(s)); end;
if (pos>line_length) or (i=tai_string(hp).len) then AsmWrite(s);
begin inc(pos,length(s));
AsmWriteLn('"'); if (pos>line_length) or (i=tai_string(hp).len) then
pos:=0; begin
end; AsmWriteLn('"');
end; pos:=0;
end;
end;
end
else
WriteAixStringConst(tai_string(hp));
end; end;
ait_label : ait_label :
@ -1112,6 +1161,30 @@ implementation
{ the dotted name is the name of the actual function entry } { the dotted name is the name of the actual function entry }
AsmWrite('.'); AsmWrite('.');
end 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 else
begin begin
if (target_info.system <> system_arm_linux) then if (target_info.system <> system_arm_linux) then
@ -1275,6 +1348,11 @@ implementation
end; end;
procedure TGNUAssembler.WriteExtraFooter;
begin
end;
procedure TGNUAssembler.WriteInstruction(hp: tai); procedure TGNUAssembler.WriteInstruction(hp: tai);
begin begin
InstrWriter.WriteInstruction(hp); InstrWriter.WriteInstruction(hp);
@ -1287,6 +1365,113 @@ implementation
end; 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; procedure TGNUAssembler.WriteAsmList;
var var
n : string; n : string;

View File

@ -52,6 +52,13 @@ unit agppcgas;
function MakeCmdLine: TCmdStr; override; function MakeCmdLine: TCmdStr; override;
end; 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]; topstr = string[4];
function getreferencestring(var ref : treference) : string; function getreferencestring(var ref : treference) : string;
@ -91,22 +98,47 @@ unit agppcgas;
if ((offset < -32768) or (offset > 32767)) and if ((offset < -32768) or (offset > 32767)) and
(refaddr = addr_no) then (refaddr = addr_no) then
internalerror(2006052501); internalerror(2006052501);
if (refaddr = addr_no) then case refaddr of
s := '' addr_no:
else s := '';
begin addr_pic_no_got:
if target_info.system in [system_powerpc_darwin,system_powerpc64_darwin] then begin
s := refaddr2str_darwin[refaddr] { used for TOC-based loads }
else if (base<>NR_RTOC) or
s :=''; (index<>NR_NO) or
s := s+'('; (offset<>0) or
if assigned(symbol) then not assigned(symbol) then
begin internalerror(2011122701);
s:=s+symbol.name; if target_asm.dollarsign<>'$' then
if assigned(relsymbol) then getreferencestring:=ReplaceForbiddenAsmSymbolChars(symbol.name)+'('+gas_regname(NR_RTOC)+')'
s:=s+'-'+relsymbol.name; else
end; getreferencestring:=symbol.name+'('+gas_regname(NR_RTOC)+')';
end; 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 if offset<0 then
s:=s+tostr(offset) s:=s+tostr(offset)
else else
@ -414,7 +446,77 @@ unit agppcgas;
end; 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 begin
RegisterAssembler(as_ppc_gas_info,TPPCGNUAssembler); RegisterAssembler(as_ppc_gas_info,TPPCGNUAssembler);
RegisterAssembler(as_ppc_gas_darwin_powerpc_info,TPPCAppleGNUAssembler); RegisterAssembler(as_ppc_gas_darwin_powerpc_info,TPPCAppleGNUAssembler);
RegisterAssembler(as_ppc_aix_powerpc_info,TPPCAIXAssembler);
end. end.

View File

@ -184,6 +184,7 @@
,as_i386_nasmhaiku ,as_i386_nasmhaiku
,as_powerpc_vasm ,as_powerpc_vasm
,as_i386_nlmcoff ,as_i386_nlmcoff
,as_powerpc_xcoff
); );
tar = (ar_none tar = (ar_none