Registerised support for Darwin/x86, both NCG and mangled.
*) -fPIC doesn't work yet with -fvia-C.
*) Apple officially requires the stack to be 16-byte-aligned,
GHC ignores this for now.
-- Other things.
| CLTD MachRep -- sign extend %eax into %edx:%eax
- | FETCHGOT Reg -- pseudo-insn for position-independent code
+ | FETCHGOT Reg -- pseudo-insn for ELF position-independent code
-- pretty-prints as
-- call 1f
-- 1: popl %reg
-- addl __GLOBAL_OFFSET_TABLE__+.-1b, %reg
-
+ | FETCHPC Reg -- pseudo-insn for Darwin position-independent code
+ -- pretty-prints as
+ -- call 1f
+ -- 1: popl %reg
+
+
data Operand
= OpReg Reg -- register
| OpImm Imm -- immediate value
needImportedSymbols = True
--- We don't need to declare any offset tables
+-- We don't need to declare any offset tables.
+-- However, for PIC on x86, we need a small helper function.
+#if i386_TARGET_ARCH
+pprGotDeclaration
+ | opt_PIC
+ = vcat [
+ ptext SLIT(".section __TEXT,__textcoal_nt,coalesced,no_toc"),
+ ptext SLIT(".weak_definition ___i686.get_pc_thunk.ax"),
+ ptext SLIT(".private_extern ___i686.get_pc_thunk.ax"),
+ ptext SLIT("___i686.get_pc_thunk.ax:"),
+ ptext SLIT("\tmovl (%esp), %eax"),
+ ptext SLIT("\tret")
+ ]
+ | otherwise = Pretty.empty
+#else
pprGotDeclaration = Pretty.empty
+#endif
-- On Darwin, we have to generate our own stub code for lazy binding..
--- There are two versions, one for PIC and one for non-PIC.
+-- For each processor architecture, there are two versions, one for PIC
+-- and one for non-PIC.
pprImportedSymbol importedLbl
+#if powerpc_TARGET_ARCH
| Just (CodeStub, lbl) <- dynamicLinkerLabelInfo importedLbl
= case opt_PIC of
False ->
ptext SLIT("\t.indirect_symbol") <+> pprCLabel_asm lbl,
ptext SLIT("\t.long dyld_stub_binding_helper")
]
-
+#elif i386_TARGET_ARCH
+ | Just (CodeStub, lbl) <- dynamicLinkerLabelInfo importedLbl
+ = case opt_PIC of
+ False ->
+ vcat [
+ ptext SLIT(".symbol_stub"),
+ ptext SLIT("L") <> pprCLabel_asm lbl <> ptext SLIT("$stub:"),
+ ptext SLIT("\t.indirect_symbol") <+> pprCLabel_asm lbl,
+ ptext SLIT("\tjmp *L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$lazy_ptr"),
+ ptext SLIT("L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$stub_binder:"),
+ ptext SLIT("\tpushl $L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$lazy_ptr"),
+ ptext SLIT("\tjmp dyld_stub_binding_helper")
+ ]
+ True ->
+ vcat [
+ ptext SLIT(".section __TEXT,__picsymbolstub2,")
+ <> ptext SLIT("symbol_stubs,pure_instructions,25"),
+ ptext SLIT("L") <> pprCLabel_asm lbl <> ptext SLIT("$stub:"),
+ ptext SLIT("\t.indirect_symbol") <+> pprCLabel_asm lbl,
+ ptext SLIT("\tcall ___i686.get_pc_thunk.ax"),
+ ptext SLIT("1:"),
+ ptext SLIT("\tmovl L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$lazy_ptr-1b(%eax),%edx"),
+ ptext SLIT("\tjmp %edx"),
+ ptext SLIT("L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$stub_binder:"),
+ ptext SLIT("\tlea L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$lazy_ptr-1b(%eax),%eax"),
+ ptext SLIT("\tpushl %eax"),
+ ptext SLIT("\tjmp dyld_stub_binding_helper")
+ ]
+ $+$ vcat [ ptext SLIT(".section __DATA, __la_sym_ptr")
+ <> (if opt_PIC then int 2 else int 3)
+ <> ptext SLIT(",lazy_symbol_pointers"),
+ ptext SLIT("L") <> pprCLabel_asm lbl <> ptext SLIT("$lazy_ptr:"),
+ ptext SLIT("\t.indirect_symbol") <+> pprCLabel_asm lbl,
+ ptext SLIT("\t.long L") <> pprCLabel_asm lbl
+ <> ptext SLIT("$stub_binder")
+ ]
+#endif
-- We also have to declare our symbol pointers ourselves:
| Just (SymbolPtr, lbl) <- dynamicLinkerLabelInfo importedLbl
= vcat [
initializePicBase :: Reg -> [NatCmmTop] -> NatM [NatCmmTop]
-#if powerpc_TARGET_ARCH && darwin_TARGET_OS
+#if darwin_TARGET_OS
-- Darwin is simple: just fetch the address of a local label.
+-- The FETCHPC pseudo-instruction is expanded to multiple instructions
+-- during pretty-printing so that we don't have to deal with the
+-- local label:
+
+-- PowerPC version:
+-- bcl 20,31,1f.
+-- 1: mflr picReg
+
+-- i386 version:
+-- call 1f
+-- 1: popl %picReg
+
initializePicBase picReg (CmmProc info lab params blocks : statics)
= return (CmmProc info lab params (b':tail blocks) : statics)
where BasicBlock bID insns = head blocks
initializePicBase picReg proc = panic "initializePicBase"
-- mingw32_TARGET_OS: not needed, won't be called
-
--- i386_TARGET_ARCH && darwin_TARGET_OS:
--- (just for completeness ;-)
--- call 1f
--- 1: popl %picReg
#endif
= ptext
IF_ARCH_alpha(SLIT("\t.text\n\t.align 3") {-word boundary-}
,IF_ARCH_sparc(SLIT(".text\n\t.align 4") {-word boundary-}
- ,IF_ARCH_i386(SLIT(".text\n\t.align 4,0x90") {-needs per-OS variation!-}
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".text\n\t.align 2"),
+ SLIT(".text\n\t.align 4,0x90"))
+ {-needs per-OS variation!-}
,IF_ARCH_x86_64(SLIT(".text\n\t.align 8") {-needs per-OS variation!-}
,IF_ARCH_powerpc(SLIT(".text\n.align 2")
,)))))
= ptext
IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
,IF_ARCH_sparc(SLIT(".data\n\t.align 8") {-<8 will break double constants -}
- ,IF_ARCH_i386(SLIT(".data\n\t.align 4")
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".data\n\t.align 2"),
+ SLIT(".data\n\t.align 4"))
,IF_ARCH_x86_64(SLIT(".data\n\t.align 8")
,IF_ARCH_powerpc(SLIT(".data\n.align 2")
,)))))
= ptext
IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
,IF_ARCH_sparc(SLIT(".data\n\t.align 8") {-<8 will break double constants -}
- ,IF_ARCH_i386(SLIT(".section .rodata\n\t.align 4")
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".const\n.align 2"),
+ SLIT(".section .rodata\n\t.align 4"))
,IF_ARCH_x86_64(SLIT(".section .rodata\n\t.align 8")
,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const\n.align 2"),
SLIT(".section .rodata\n\t.align 2"))
= ptext
IF_ARCH_alpha(SLIT("\t.data\n\t.align 3")
,IF_ARCH_sparc(SLIT(".data\n\t.align 8") {-<8 will break double constants -}
- ,IF_ARCH_i386(SLIT(".section .rodata\n\t.align 4")
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".const_data\n.align 2"),
+ SLIT(".section .rodata\n\t.align 4"))
,IF_ARCH_x86_64(SLIT(".section .rodata\n\t.align 8")
,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const_data\n.align 2"),
SLIT(".data\n\t.align 2"))
= ptext
IF_ARCH_alpha(SLIT("\t.bss\n\t.align 3")
,IF_ARCH_sparc(SLIT(".bss\n\t.align 8") {-<8 will break double constants -}
- ,IF_ARCH_i386(SLIT(".section .bss\n\t.align 4")
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".const_data\n\t.align 2"),
+ SLIT(".section .bss\n\t.align 4"))
,IF_ARCH_x86_64(SLIT(".section .bss\n\t.align 8")
,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const_data\n.align 2"),
SLIT(".section .bss\n\t.align 2"))
= ptext
IF_ARCH_alpha(SLIT("\t.data\n\t.align 4")
,IF_ARCH_sparc(SLIT(".data\n\t.align 16")
- ,IF_ARCH_i386(SLIT(".section .rodata\n\t.align 16")
+ ,IF_ARCH_i386(IF_OS_darwin(SLIT(".const\n.align 4"),
+ SLIT(".section .rodata\n\t.align 16"))
,IF_ARCH_x86_64(SLIT(".section .rodata.cst16\n\t.align 16")
,IF_ARCH_powerpc(IF_OS_darwin(SLIT(".const\n.align 4"),
SLIT(".section .rodata\n\t.align 4"))
pprAlign bytes =
IF_ARCH_alpha(ptextSLIT(".align ") <> int pow2,
- IF_ARCH_i386(ptext SLIT(".align ") <> int bytes,
+ IF_ARCH_i386(ptext SLIT(".align ") <> int IF_OS_darwin(pow2,bytes),
IF_ARCH_x86_64(ptext SLIT(".align ") <> int bytes,
IF_ARCH_sparc(ptext SLIT(".align ") <> int bytes,
IF_ARCH_powerpc(ptext SLIT(".align ") <> int pow2,)))))
pprInstr (CVTSI2SD from to) = pprOpReg SLIT("cvtsi2sd") from to
#endif
+ -- FETCHGOT for PIC on ELF platforms
pprInstr (FETCHGOT reg)
= vcat [ ptext SLIT("\tcall 1f"),
hcat [ ptext SLIT("1:\tpopl\t"), pprReg I32 reg ],
pprReg I32 reg ]
]
+ -- FETCHPC for PIC on Darwin/x86
+ -- get the instruction pointer into a register
+ -- (Terminology note: the IP is called Program Counter on PPC,
+ -- and it's a good thing to use the same name on both platforms)
+pprInstr (FETCHPC reg)
+ = vcat [ ptext SLIT("\tcall 1f"),
+ hcat [ ptext SLIT("1:\tpopl\t"), pprReg I32 reg ]
+ ]
+
+
+
#endif
-- -----------------------------------------------------------------------------
#endif
FETCHGOT reg -> mkRU [] [reg]
+ FETCHPC reg -> mkRU [] [reg]
COMMENT _ -> noUsage
DELTA _ -> noUsage
CALL (Right reg) p -> CALL (Right (env reg)) p
FETCHGOT reg -> FETCHGOT (env reg)
-
+ FETCHPC reg -> FETCHPC (env reg)
+
NOP -> instr
COMMENT _ -> instr
DELTA _ -> instr
$T_HDR_vector = "\t\.text\n\t\.align 2\n";
#--------------------------------------------------------#
- } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ ) {
+ } elsif ( $TargetPlatform =~ /^powerpc-apple-darwin.*/ ) {
# Apple PowerPC Darwin/MacOS X.
$T_STABBY = 0; # 1 iff .stab things (usually if a.out format)
$T_US = '_'; # _ if symbols have an underscore on the front
$T_HDR_vector = "\t\.text\n\t\.align 2\n";
#--------------------------------------------------------#
+ } elsif ( $TargetPlatform =~ /^i386-apple-darwin.*/ ) {
+ # Apple PowerPC Darwin/MacOS X.
+ $T_STABBY = 0; # 1 iff .stab things (usually if a.out format)
+ $T_US = '_'; # _ if symbols have an underscore on the front
+ $T_PRE_APP = 'DOESNT APPLY'; # regexp that says what comes before APP/NO_APP
+ $T_CONST_LBL = '^\LC\d+:'; # regexp for what such a lbl looks like
+ $T_POST_LBL = ':';
+ $T_X86_PRE_LLBL_PAT = 'L';
+ $T_X86_PRE_LLBL = 'L';
+ $T_X86_BADJMP = '^\tjmp [^L\*]';
+
+ $T_MOVE_DIRVS = '^(\s*(\.align \d+|\.text|\.data|\.const_data|\.cstring|\.non_lazy_symbol_pointer|\.const|\.static_const|\.literal4|\.literal8|\.static_data|\.globl \S+|\.section .*|\.lcomm.*)\n)';
+ $T_COPY_DIRVS = '\.(globl|lcomm)';
+
+ $T_DOT_WORD = '\.(long|short|byte|fill|space)';
+ $T_DOT_GLOBAL = '\.globl';
+ $T_HDR_toc = "\.toc\n";
+ $T_HDR_literal = "\t\.const\n\t\.align 2\n";
+ $T_HDR_misc = "\t\.text\n\t\.align 2\n";
+ $T_HDR_data = "\t\.data\n\t\.align 2\n";
+ $T_HDR_rodata = "\t\.const\n\t\.align 2\n";
+ $T_HDR_relrodata= "\t\.const_data\n\t\.align 2\n";
+ $T_HDR_closure = "\t\.data\n\t\.align 2\n";
+ $T_HDR_info = "\t\.text\n\t\.align 2\n";
+ $T_HDR_entry = "\t\.text\n\t\.align 2\n";
+ $T_HDR_vector = "\t\.text\n\t\.align 2\n";
+
+ #--------------------------------------------------------#
} elsif ( $TargetPlatform =~ /^powerpc-.*-linux/ ) {
# PowerPC Linux
$T_STABBY = 0; # 1 iff .stab things (usually if a.out format)
# The .no_dead_strip directives are actually put there by
# the gcc3 "used" attribute on entry points.
- } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && (
+ } elsif ( $TargetPlatform =~ /^.*-apple-darwin.*/ && (
/^\s*\.picsymbol_stub/
- || /^\s*\.section __TEXT,__picsymbol_stub1,.*/
- || /^\s*\.section __TEXT,__picsymbolstub1,.*/
+ || /^\s*\.section __TEXT,__picsymbol_stub\d,.*/
+ || /^\s*\.section __TEXT,__picsymbolstub\d,.*/
|| /^\s*\.symbol_stub/
- || /^\s*\.section __TEXT,__symbol_stub1,.*/
- || /^\s*\.section __TEXT,__symbolstub1,.*/
+ || /^\s*\.section __TEXT,__symbol_stub\d,.*/
+ || /^\s*\.section __TEXT,__symbolstub\d,.*/
|| /^\s*\.lazy_symbol_pointer/
|| /^\s*\.non_lazy_symbol_pointer/ ))
{
$chkcat[$i] = 'dyld';
$chksymb[$i] = '';
- } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && $chkcat[$i] eq 'dyld' && /^\s*\.data/)
+ } elsif ( $TargetPlatform =~ /^.*-apple-darwin.*/ && $chkcat[$i] eq 'dyld' && /^\s*\.data/)
{ # non_lazy_symbol_ptrs that point to local symbols
$chk[++$i] = $_;
$chkcat[$i] = 'dyld';
$chkcat[$i] = 'misc';
$chksymb[$i] = $1;
+ } elsif ( $TargetPlatform =~ /^i386-apple-darwin/ && /^(___i686\.get_pc_thunk\.[abcd]x):/o) {
+ # To handle PIC on Darwin/x86, we need to appropriately pass through
+ # the get_pc_thunk functions. The need to be put into a special section
+ # marked as coalesced (otherwise the .weak_definition doesn't work
+ # on Darwin).
+ $chk[++$i] = $_;
+ $chkcat[$i] = 'get_pc_thunk';
+ $chksymb[$i] = $1;
+
} elsif ( /^${T_US}[A-Za-z0-9_]/o
&& ( $TargetPlatform !~ /^hppa/ # need to avoid local labels in this case
|| ! /^L\$\d+$/ )
$r = $& . $r;
}
+ if ($TargetPlatform =~ /^i386-apple-darwin/) {
+ $pcrel_label = $p;
+ $pcrel_label =~ s/(.|\n)*^(\"?L\d+\$pb\"?):\n(.|\n)*/$2/ or $pcrel_label = "";
+ $pcrel_reg = $p;
+ $pcrel_reg =~ s/(.|\n)*.*___i686\.get_pc_thunk\.([abcd]x)\n(.|\n)*/$2/ or $pcrel_reg = "";
+ $p =~ s/^\s+call\s+___i686\.get_pc_thunk\..x//;
+ $p =~ s/^\"?L\d+\$pb\"?:\n//;
+
+ if ($pcrel_reg eq "bx") {
+ # Bad gcc. Goes and uses %ebx, our BaseReg, for PIC. Bad gcc.
+ die "Darwin/x86: -fPIC -via-C doesn't work yet, use -fasm. Aborting."
+ }
+ }
+
} elsif ($TargetPlatform =~ /^x86_64-/) {
$p =~ s/^\tpushq\s+\%r(bx|bp|12|13|14)\n//g;
$p =~ s/^\tmovq\s+\%r(bx|bp|12|13|14),\s*\d*\(\%rsp\)\n//g;
$p =~ s/^\tsw\t\$fp,\d+\(\$sp\)\n//;
$p =~ s/^\tsw\t\$28,\d+\(\$sp\)\n//;
$p =~ s/__FRAME__/$FRAME/;
- } elsif ($TargetPlatform =~ /^powerpc-apple-.*/) {
+ } elsif ($TargetPlatform =~ /^powerpc-apple-darwin.*/) {
$pcrel_label = $p;
$pcrel_label =~ s/(.|\n)*^(\"?L\d+\$pb\"?):\n(.|\n)*/$2/ or $pcrel_label = "";
die "Prologue junk?: $p\n" if $p =~ /^\s+[^\s\.]/;
# For PIC, we want to keep part of the prologue
- if ($TargetPlatform =~ /^powerpc-apple-.*/ && $pcrel_label ne "") {
+ if ($TargetPlatform =~ /^powerpc-apple-darwin.*/ && $pcrel_label ne "") {
# Darwin: load the current instruction pointer into register r31
$p .= "bcl 20,31,$pcrel_label\n";
$p .= "$pcrel_label:\n";
$p .= "\tmflr 30\n";
$p .= "\tlwz 0,.LCL$pcrel_label-.LCF$pcrel_label(30)\n";
$p .= "\tadd 30,0,30\n";
+ } elsif ($TargetPlatform =~ /^i386-apple-darwin.*/ && $pcrel_label ne "") {
+ $p .= "\tcall ___i686.get_pc_thunk.$pcrel_reg\n";
+ $p .= "$pcrel_label:\n";
}
# glue together what's left
$e =~ s/^\tlw\t\$fp,\d+\(\$sp\)\n//;
$e =~ s/^\taddu\t\$sp,\$sp,\d+\n//;
$e =~ s/^\tj\t\$31\n//;
- } elsif ($TargetPlatform =~ /^powerpc-apple-.*/) {
+ } elsif ($TargetPlatform =~ /^powerpc-apple-darwin.*/) {
$e =~ s/^\taddi r1,r1,\d+\n//;
$e =~ s/^\tlwz r\d+,\d+\(r1\)\n//;
$e =~ s/^\tlmw r\d+,-\d+\(r1\)\n//;
# toss all calls to __DISCARD__
$c =~ s/^\t(call|jbsr|jal)\s+${T_US}__DISCARD__\n//go;
$c =~ s/^\tjsr\s+\$26\s*,\s*${T_US}__DISCARD__\n//go if $TargetPlatform =~ /^alpha-/;
- $c =~ s/^\tbl\s+L___DISCARD__\$stub\n//go if $TargetPlatform =~ /^powerpc-apple-.*/;
+ $c =~ s/^\tbl\s+L___DISCARD__\$stub\n//go if $TargetPlatform =~ /^powerpc-apple-darwin.*/;
$c =~ s/^\tbl\s+__DISCARD__(\@plt)?\n//go if $TargetPlatform =~ /^powerpc-.*-linux/;
$c =~ s/^\tbl\s+\.__DISCARD__\n\s+nop\n//go if $TargetPlatform =~ /^powerpc64-.*-linux/;
+ $c =~ s/^\tcall\s+L___DISCARD__\$stub\n//go if $TargetPlatform =~ /i386-apple-darwin.*/;
# IA64: mangle tailcalls into jumps here
if ($TargetPlatform =~ /^ia64-/) {
$j++;
}
- } elsif ( $TargetPlatform =~ /^powerpc-apple-.*/ && $chkcat[$i] eq 'dyld' ) {
- # powerpc-apple: dynamic linker stubs
+ } elsif ( $TargetPlatform =~ /^.*-apple-darwin.*/ && $chkcat[$i] eq 'dyld' ) {
+ # apple-darwin: dynamic linker stubs
if($chk[$i] !~ /\.indirect_symbol ___DISCARD__/)
{ # print them out unchanged, but remove the stubs for __DISCARD__
print OUTASM $chk[$i];
}
+ } elsif ( $TargetPlatform =~ /^i386-apple-darwin.*/ && $chkcat[$i] eq 'get_pc_thunk' ) {
+ # i386-apple-darwin: __i686.get_pc_thunk.[abcd]x
+ print OUTASM ".section __TEXT,__textcoal_nt,coalesced,no_toc\n";
+ print OUTASM $chk[$i];
} else {
&tidy_up_and_die(1,"$Pgm: unknown chkcat (ghc-asm: $TargetPlatform)\n$chkcat[$i]\n$chk[$i]\n");
}
#ifdef i386_HOST_ARCH
+#ifdef darwin_TARGET_OS
+#define STG_GLOBAL ".globl "
+#else
+#define STG_GLOBAL ".global "
+#endif
+
StgThreadReturnCode
StgRun(StgFunPtr f, StgRegTable *basereg) {
"movl %2,%%eax\n\t"
"jmp *%%eax\n\t"
- ".global " STG_RETURN "\n"
+ STG_GLOBAL STG_RETURN "\n"
STG_RETURN ":\n\t"
"movl %%esi, %%eax\n\t" /* Return value in R1 */