[PATCH 09/22] winebuild: Add PPC64 support
André Hentschel
nerv at dawncrow.de
Sun Aug 16 14:01:47 CDT 2020
Signed-off-by: André Hentschel <nerv at dawncrow.de>
---
tools/winebuild/build.h | 4 +-
tools/winebuild/import.c | 272 +++++++++++++++++++++++++++++++++++++++
tools/winebuild/main.c | 2 +
tools/winebuild/parser.c | 4 +-
tools/winebuild/spec32.c | 37 +++---
tools/winebuild/utils.c | 47 ++++---
6 files changed, 329 insertions(+), 37 deletions(-)
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h
index e1d2e5edf85..36e06bcfad1 100644
--- a/tools/winebuild/build.h
+++ b/tools/winebuild/build.h
@@ -144,7 +144,7 @@ typedef struct
enum target_cpu
{
- CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_LAST = CPU_ARM64
+ CPU_x86, CPU_x86_64, CPU_POWERPC, CPU_ARM, CPU_ARM64, CPU_POWERPC64, CPU_LAST = CPU_POWERPC64
};
enum target_platform
@@ -186,7 +186,7 @@ struct strarray
#define FLAG_CPU(cpu) (0x10000 << (cpu))
#define FLAG_CPU_MASK (FLAG_CPU(CPU_LAST + 1) - FLAG_CPU(0))
-#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64))
+#define FLAG_CPU_WIN64 (FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64))
#define FLAG_CPU_WIN32 (FLAG_CPU_MASK & ~FLAG_CPU_WIN64)
#define MAX_ORDINALS 65535
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index da9ad620225..9543e433ac1 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -3,6 +3,8 @@
*
* Copyright 2000, 2004 Alexandre Julliard
* Copyright 2000 Eric Pouech
+ * Copyright 2009-2013, 2015, 2017, 2020 André Hentschel
+ * Copyright 2019 Timothy Pearson <tpearson at raptorengineering.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -787,6 +789,20 @@ static void output_import_thunk( const char *name, const char *table, int pos )
output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) );
output( "\tbctr\n" );
break;
+ case CPU_POWERPC64:
+ /*
+ * The ppc64 ABIv2 expects r12 to be set to ctr before bctr for PLT-like calls.
+ * ABIv2-compatible functions attempt to rebuild the TOC pointer (r2) from r12 under this assumption.
+ */
+ output( "\tlis %s, (%s+%d)@highest\n", ppc_reg(12), table, pos );
+ output( "\tori %s, %s, (%s+%d)@higher\n", ppc_reg(12), ppc_reg(12), table, pos );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, (%s+%d)@high\n", ppc_reg(12), ppc_reg(12), table, pos );
+ output( "\tori %s, %s, (%s+%d)@l\n", ppc_reg(12), ppc_reg(12), table, pos );
+ output( "\tld %s, 0(%s)\n", ppc_reg(12), ppc_reg(12) );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctr\n" );
+ break;
}
output_cfi( ".cfi_endproc" );
output_function_size( name );
@@ -1137,6 +1153,54 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
output( "\tmtlr %s\n", ppc_reg(0));
output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
+ /* branch to ctr register. */
+ output( "\tbctr\n");
+ break;
+ case CPU_POWERPC64:
+ /* Save all callee saved registers into a stackframe. */
+ output( "\tstdu %s, -%d(%s)\n",ppc_reg(1), 176, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(3), 48, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(4), 56, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(5), 64, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(6), 72, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(7), 80, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(8), 88, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(9), 96, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(10),104, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(11),112, ppc_reg(1));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(12),120, ppc_reg(1));
+ /* r0 -> r3 (arg1) */
+ output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
+ /* Call the __wine_delay_load function, arg1 is arg1. */
+ output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("__wine_spec_delay_load") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctrl\n" );
+ output( "\tld %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1));
+ /* r3 (return value) -> r12 (branch / ctr) */
+ output( "\tmr %s, %s\n", ppc_reg(12), ppc_reg(3));
+ /* Load return value from call into ctr register */
+ output( "\tmtctr %s\n", ppc_reg(12));
+ /* restore all saved registers and drop stackframe. */
+ output( "\tld %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(3), 48, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(4), 56, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(5), 64, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(6), 72, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(7), 80, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(8), 88, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(9), 96, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(10),104, ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(11),112, ppc_reg(1));
+ /* don't restore r12! restoring r12 here would corrupt the computed TOC post-bctr. */
+ /* Load return value from call into return register */
+ output( "\tld %s, 0(%s)\n", ppc_reg(1), ppc_reg(1));
+ output( "\tld %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1));
+ output( "\tmtlr %s\n", ppc_reg(0));
/* branch to ctr register. */
output( "\tbctr\n");
break;
@@ -1218,6 +1282,23 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
break;
}
break;
+ case CPU_POWERPC64:
+ output( "\tmflr %s\n", ppc_reg(0));
+ output( "\tstd %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1)); /* save return address */
+ output( "\tlis %s, %d at highest\n", ppc_reg(12), (idx << 16) | j );
+ output( "\tori %s, %s, %d at higher\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %d at high\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+ output( "\tori %s, %s, %d at l\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j );
+ output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(12) );
+ output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("__wine_delay_load_asm") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctr\n" );
+ break;
}
output_cfi( ".cfi_endproc" );
}
@@ -1380,6 +1461,37 @@ void output_stubs( DLLSPEC *spec )
output( "\tadd x2, x2, #:lo12:%s\n", asm_name("__wine_spec_unimplemented_stub") );
output( "\tblr x2\n" );
break;
+ case CPU_POWERPC64:
+ /* Clobbers r3, r4, and r12 */
+ output( "\tlis %s, .L__wine_spec_file_name at highest\n", ppc_reg(3) );
+ output( "\tori %s, %s, .L__wine_spec_file_name at higher\n", ppc_reg(3), ppc_reg(3) );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(3), ppc_reg(3) );
+ output( "\toris %s, %s, .L__wine_spec_file_name at high\n", ppc_reg(3), ppc_reg(3) );
+ output( "\tori %s, %s, .L__wine_spec_file_name at l\n", ppc_reg(3), ppc_reg(3) );
+ if (exp_name)
+ {
+ output( "\tlis %s, .L%s_string at highest\n", ppc_reg(4), name );
+ output( "\tori %s, %s, .L%s_string at higher\n", ppc_reg(4), ppc_reg(4), name );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(4), ppc_reg(4) );
+ output( "\toris %s, %s, .L%s_string at high\n", ppc_reg(4), ppc_reg(4), name );
+ output( "\tori %s, %s, .L%s_string at l\n", ppc_reg(4), ppc_reg(4), name );
+ }
+ else
+ {
+ output( "\tlis %s, %u at highest\n", ppc_reg(4), odp->ordinal );
+ output( "\tori %s, %s, %u at higher\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(4), ppc_reg(4) );
+ output( "\toris %s, %s, %u at high\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+ output( "\tori %s, %s, %u at l\n", ppc_reg(4), ppc_reg(4), odp->ordinal );
+ }
+ output( "\tlis %s, __wine_spec_unimplemented_stub at highest\n", ppc_reg(12) );
+ output( "\tori %s, %s, __wine_spec_unimplemented_stub at higher\n", ppc_reg(12), ppc_reg(12) );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, __wine_spec_unimplemented_stub at high\n", ppc_reg(12), ppc_reg(12) );
+ output( "\tori %s, %s, __wine_spec_unimplemented_stub at l\n", ppc_reg(12), ppc_reg(12) );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctr\n" );
+ break;
default:
assert(0);
}
@@ -1657,6 +1769,137 @@ void output_syscalls( DLLSPEC *spec )
output( "\tmovk x0, #0x%x\n", invalid_param & 0x0000ffff );
output( "\tret\n" );
break;
+ case CPU_POWERPC64:
+ output( "\tlis %s, %u at highest\n", ppc_reg(12), count );
+ output( "\tori %s, %s, %u at higher\n", ppc_reg(12), ppc_reg(12), count );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %u at high\n", ppc_reg(12), ppc_reg(12), count );
+ output( "\tori %s, %s, %u at l\n", ppc_reg(12), ppc_reg(12), count );
+ output( "\tcmpw cr7, %s, %s\n", ppc_reg(11), ppc_reg(12) );
+ output( "\tbgt cr7, 3f\n" );
+ /* save return address (thunk_addr) */
+ output( "\tmflr %s\n", ppc_reg(0) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1) );
+ /* Save all callee saved registers into the syscall_frame. */
+ output( "\tstdu %s, -%d(%s)\n",ppc_reg(1), 256, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(3), 32, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(4), 40, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(5), 48, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(6), 56, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(7), 64, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(8), 72, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(9), 80, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(10), 88, ppc_reg(1) );
+ /* Save all nonvolatile registers into the syscall_frame. */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(14), 112, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(15), 120, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(16), 128, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(17), 136, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(18), 144, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(19), 152, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(20), 160, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(21), 168, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(22), 176, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(23), 184, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(24), 192, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(25), 200, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(26), 208, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(27), 216, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(28), 224, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(29), 232, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(30), 240, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(31), 248, ppc_reg(1) );
+ output( "\tmr %s, %s\n", ppc_reg(15), ppc_reg(11) );
+ output( "\tmr %s, %s\n", ppc_reg(18), ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(11), 296, ppc_reg(1) );
+ output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("NtCurrentTeb") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("NtCurrentTeb") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("NtCurrentTeb") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("NtCurrentTeb") );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctrl\n" );
+ /* ppc64_thread_data()->syscall_frame */
+ output( "\taddi %s, %s, 0x200\n", ppc_reg(3), ppc_reg(3) );
+ output( "\taddi %s, %s, 0x0f0\n", ppc_reg(3), ppc_reg(3) );
+ output( "\taddi %s, %s, 0x008\n", ppc_reg(19), ppc_reg(3) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(3), 32, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(4), 40, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(5), 48, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(6), 56, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(7), 64, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(8), 72, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(9), 80, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(10), 88, ppc_reg(1) );
+ output( "\tld %s, 0(%s)\n", ppc_reg(14), ppc_reg(19) ); /* prev frame */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(14), 96, ppc_reg(1) );
+ output( "\tstd %s, 0(%s)\n", ppc_reg(1), ppc_reg(19) ); /* syscall frame */
+ output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name(".Lsyscall_args") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_args") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_args") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_args") );
+ output( "\tadd %s, %s, %s\n", ppc_reg(12), ppc_reg(12), ppc_reg(15) );
+ output( "\tlbz %s, 0(%s)\n", ppc_reg(16), ppc_reg(12) );
+ output( "\taddi %s, %s, -64\n", ppc_reg(16), ppc_reg(16) );
+ output( "\tcmpwi cr7, %s, 0\n", ppc_reg(16) );
+ output( "\textsw %s, %s\n", ppc_reg(16), ppc_reg(16) );
+ output( "\tble cr7, 2f\n" );
+ output( "\taddi %s, %s, %d\n", ppc_reg(17), ppc_reg(1), 256 + 64 + 96); /* this function + prev function (thunk) + parameter save area */
+ output( "\tsub %s, %s, %s\n", ppc_reg(1), ppc_reg(1), ppc_reg(16) );
+ output( "\taddi %s, %s, -%d\n", ppc_reg(1), ppc_reg(1), 96 );
+ output( "\trldicr %s, %s, 0, 59\n", ppc_reg(1), ppc_reg(1) ); /* align sp */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(18), 0, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1) );
+ output( "\taddi %s, %s, %d\n", ppc_reg(20), ppc_reg(1), 96 ); /* new parameter save area */
+ output( "1:\taddi %s, %s, -%d\n", ppc_reg(16), ppc_reg(16), 8 );
+ output( "\tldx %s, %s, %s\n", ppc_reg(0), ppc_reg(17), ppc_reg(16) );
+ output( "\tstdx %s, %s, %s\n", ppc_reg(0), ppc_reg(20), ppc_reg(16) );
+ output( "\tcmpwi cr7, %s, 0\n", ppc_reg(16) );
+ output( "\tbne cr7, 1b\n" );
+ output( "2:\tlis %s, %s at highest\n", ppc_reg(12), asm_name(".Lsyscall_table") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_table") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_table") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_table") );
+ output( "\trldicr %s, %s, 3, 60\n", ppc_reg(17), ppc_reg(15) );
+ output( "\tadd %s, %s, %s\n", ppc_reg(17), ppc_reg(17), ppc_reg(12) );
+ output( "\tld %s, 0(%s)\n", ppc_reg(12), ppc_reg(17) );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctrl\n" );
+ output( "\tmr %s, %s\n", ppc_reg(1), ppc_reg(18) );
+ output( "\tstd %s, 0(%s)\n", ppc_reg(14), ppc_reg(19) ); /* prev frame */
+ output( "\tld %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(14), 112, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(15), 120, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(16), 128, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(17), 136, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(18), 144, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(19), 152, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(20), 160, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(21), 168, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(22), 176, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(23), 184, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(24), 192, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(25), 200, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(26), 208, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(27), 216, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(28), 224, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(29), 232, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(30), 240, ppc_reg(1) );
+ output( "\tld %s, %d(%s)\n", ppc_reg(31), 248, ppc_reg(1) );
+ output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 256 ); /* restore sp */
+ output( "\tld %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1) );
+ output( "\tmtlr %s\n", ppc_reg(0) );
+ output( "\tblr\n" );
+ output( "3:\tlis %s, %u at highest\n", ppc_reg(3), invalid_param );
+ output( "\tori %s, %s, %u at higher\n", ppc_reg(3), ppc_reg(3), invalid_param );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(3), ppc_reg(3) );
+ output( "\toris %s, %s, %u at high\n", ppc_reg(3), ppc_reg(3), invalid_param );
+ output( "\tori %s, %s, %u at l\n", ppc_reg(3), ppc_reg(3), invalid_param );
+ output( "\tblr\n" );
+ break;
default:
assert(0);
}
@@ -1747,6 +1990,35 @@ void output_syscalls( DLLSPEC *spec )
output( "\tldp x29, x30, [sp], #16\n" );
output( "\tret\n" );
break;
+ case CPU_POWERPC64:
+ output( "\tmflr %s\n", ppc_reg(0) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1) ); /* save lr */
+ output( "\tstdu %s, -%d(%s)\n",ppc_reg(1), 64, ppc_reg(1) );
+ output( "\tstd %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1) ); /* save r2 */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(0), 32, ppc_reg(1) ); /* save lr again */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(11), 40, ppc_reg(1) ); /* save r11 */
+ output( "\tstd %s, %d(%s)\n", ppc_reg(12), 48, ppc_reg(1) ); /* save r12 */
+ output( "\tlis %s, %s at highest\n", ppc_reg(12), asm_name("__wine_syscall_dispatcher") );
+ output( "\tori %s, %s, %s at higher\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_syscall_dispatcher") );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(12), ppc_reg(12) );
+ output( "\toris %s, %s, %s at high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_syscall_dispatcher") );
+ output( "\tori %s, %s, %s at l\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_syscall_dispatcher") );
+ output( "\tld %s, 0(%s)\n", ppc_reg(12), ppc_reg(12) );
+ output( "\tlis %s, %u at highest\n", ppc_reg(11), i );
+ output( "\tori %s, %s, %u at higher\n", ppc_reg(11), ppc_reg(11), i );
+ output( "\trldicr %s, %s, 32, 31\n", ppc_reg(11), ppc_reg(11) );
+ output( "\toris %s, %s, %u at high\n", ppc_reg(11), ppc_reg(11), i );
+ output( "\tori %s, %s, %u at l\n", ppc_reg(11), ppc_reg(11), i );
+ output( "\tmtctr %s\n", ppc_reg(12) );
+ output( "\tbctrl\n" );
+ output( "\tld %s, %d(%s)\n", ppc_reg(12), 48, ppc_reg(1) ); /* restore r12 */
+ output( "\tld %s, %d(%s)\n", ppc_reg(11), 40, ppc_reg(1) ); /* restore r11 */
+ output( "\tld %s, %d(%s)\n", ppc_reg(2), 24, ppc_reg(1) ); /* restore r2 */
+ output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 64 ); /* restore sp */
+ output( "\tld %s, %d(%s)\n", ppc_reg(0), 16, ppc_reg(1) ); /* restore lr */
+ output( "\tmtlr %s\n", ppc_reg(0) );
+ output( "\tblr\n" );
+ break;
default:
assert(0);
}
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index 0e5e1627dda..02471ccbee1 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -54,6 +54,8 @@ int safe_seh = 0;
enum target_cpu target_cpu = CPU_x86;
#elif defined(__x86_64__)
enum target_cpu target_cpu = CPU_x86_64;
+#elif defined(__powerpc64__)
+enum target_cpu target_cpu = CPU_POWERPC64;
#elif defined(__powerpc__)
enum target_cpu target_cpu = CPU_POWERPC;
#elif defined(__arm__)
diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c
index 54fffd8a1b2..66ec693d039 100644
--- a/tools/winebuild/parser.c
+++ b/tools/winebuild/parser.c
@@ -432,9 +432,9 @@ static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec )
odp->link_name = xstrdup("");
/* don't bother generating stubs for Winelib */
if (odp->flags & FLAG_CPU_MASK)
- odp->flags &= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
+ odp->flags &= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64);
else
- odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64);
+ odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64) | FLAG_CPU(CPU_ARM) | FLAG_CPU(CPU_ARM64) | FLAG_CPU(CPU_POWERPC64);
return parse_spec_arguments( odp, spec, 1 );
}
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index c85249b2a96..3b3a84a3d88 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -32,12 +32,13 @@
#include "build.h"
-#define IMAGE_FILE_MACHINE_UNKNOWN 0
-#define IMAGE_FILE_MACHINE_I386 0x014c
-#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
-#define IMAGE_FILE_MACHINE_AMD64 0x8664
-#define IMAGE_FILE_MACHINE_ARMNT 0x01C4
-#define IMAGE_FILE_MACHINE_ARM64 0xaa64
+#define IMAGE_FILE_MACHINE_UNKNOWN 0
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
+#define IMAGE_FILE_MACHINE_POWERPC64 0x01f2
+#define IMAGE_FILE_MACHINE_AMD64 0x8664
+#define IMAGE_FILE_MACHINE_ARMNT 0x01C4
+#define IMAGE_FILE_MACHINE_ARM64 0xaa64
#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
@@ -593,7 +594,6 @@ void output_exports( DLLSPEC *spec )
}
}
-
/*******************************************************************
* output_module
*
@@ -636,6 +636,7 @@ void output_module( DLLSPEC *spec )
break;
case CPU_ARM64:
case CPU_POWERPC:
+ case CPU_POWERPC64:
output( "\n\t.section \".init\",\"ax\"\n" );
output( "\tb 1f\n" );
break;
@@ -657,11 +658,12 @@ void output_module( DLLSPEC *spec )
output( "\t.long 0x4550\n" ); /* Signature */
switch(target_cpu)
{
- case CPU_x86: machine = IMAGE_FILE_MACHINE_I386; break;
- case CPU_x86_64: machine = IMAGE_FILE_MACHINE_AMD64; break;
- case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break;
- case CPU_ARM: machine = IMAGE_FILE_MACHINE_ARMNT; break;
- case CPU_ARM64: machine = IMAGE_FILE_MACHINE_ARM64; break;
+ case CPU_x86: machine = IMAGE_FILE_MACHINE_I386; break;
+ case CPU_x86_64: machine = IMAGE_FILE_MACHINE_AMD64; break;
+ case CPU_POWERPC: machine = IMAGE_FILE_MACHINE_POWERPC; break;
+ case CPU_POWERPC64: machine = IMAGE_FILE_MACHINE_POWERPC64; break;
+ case CPU_ARM: machine = IMAGE_FILE_MACHINE_ARMNT; break;
+ case CPU_ARM64: machine = IMAGE_FILE_MACHINE_ARM64; break;
}
output( "\t.short 0x%04x\n", /* Machine */
machine );
@@ -810,11 +812,12 @@ void output_fake_module( DLLSPEC *spec )
put_dword( 0x4550 ); /* Signature */
switch(target_cpu)
{
- case CPU_x86: put_word( IMAGE_FILE_MACHINE_I386 ); break;
- case CPU_x86_64: put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
- case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
- case CPU_ARM: put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
- case CPU_ARM64: put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
+ case CPU_x86: put_word( IMAGE_FILE_MACHINE_I386 ); break;
+ case CPU_x86_64: put_word( IMAGE_FILE_MACHINE_AMD64 ); break;
+ case CPU_POWERPC: put_word( IMAGE_FILE_MACHINE_POWERPC ); break;
+ case CPU_POWERPC64: put_word( IMAGE_FILE_MACHINE_POWERPC64 ); break;
+ case CPU_ARM: put_word( IMAGE_FILE_MACHINE_ARMNT ); break;
+ case CPU_ARM64: put_word( IMAGE_FILE_MACHINE_ARM64 ); break;
}
put_word( nb_sections ); /* NumberOfSections */
put_dword( 0 ); /* TimeDateStamp */
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 07ef2ed2989..702964219c6 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -52,21 +52,23 @@ static const struct
enum target_cpu cpu;
} cpu_names[] =
{
- { "i386", CPU_x86 },
- { "i486", CPU_x86 },
- { "i586", CPU_x86 },
- { "i686", CPU_x86 },
- { "i786", CPU_x86 },
- { "amd64", CPU_x86_64 },
- { "x86_64", CPU_x86_64 },
- { "powerpc", CPU_POWERPC },
- { "arm", CPU_ARM },
- { "armv5", CPU_ARM },
- { "armv6", CPU_ARM },
- { "armv7", CPU_ARM },
- { "armv7a", CPU_ARM },
- { "arm64", CPU_ARM64 },
- { "aarch64", CPU_ARM64 },
+ { "i386", CPU_x86 },
+ { "i486", CPU_x86 },
+ { "i586", CPU_x86 },
+ { "i686", CPU_x86 },
+ { "i786", CPU_x86 },
+ { "amd64", CPU_x86_64 },
+ { "x86_64", CPU_x86_64 },
+ { "powerpc", CPU_POWERPC },
+ { "powerpc64", CPU_POWERPC64 },
+ { "powerpc64le", CPU_POWERPC64 },
+ { "arm", CPU_ARM },
+ { "armv5", CPU_ARM },
+ { "armv6", CPU_ARM },
+ { "armv7", CPU_ARM },
+ { "armv7a", CPU_ARM },
+ { "arm64", CPU_ARM64 },
+ { "aarch64", CPU_ARM64 },
};
/* atexit handler to clean tmp files */
@@ -425,6 +427,7 @@ struct strarray get_as_command(void)
switch(target_cpu)
{
case CPU_POWERPC:
+ case CPU_POWERPC64:
strarray_add_one( &args, (force_pointer_size == 8) ? "-a64" : "-a32" );
break;
default:
@@ -471,6 +474,10 @@ struct strarray get_ld_command(void)
case CPU_POWERPC:
strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64ppc" : "elf32ppc", NULL );
break;
+ case CPU_POWERPC64:
+ /* We only respect the little endian version for now */
+ strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf64lppc" : "elf32lppc", NULL );
+ break;
default:
strarray_add( &args, "-m", (force_pointer_size == 8) ? "elf_x86_64" : "elf_i386", NULL );
break;
@@ -1023,6 +1030,7 @@ unsigned int get_alignment(unsigned int align)
if (target_platform != PLATFORM_APPLE) return align;
/* fall through */
case CPU_POWERPC:
+ case CPU_POWERPC64:
case CPU_ARM:
case CPU_ARM64:
n = 0;
@@ -1037,7 +1045,13 @@ unsigned int get_alignment(unsigned int align)
/* return the page size for the target CPU */
unsigned int get_page_size(void)
{
- return 0x1000; /* same on all platforms */
+ switch(target_cpu)
+ {
+ case CPU_POWERPC64:
+ return 0x10000;
+ default:
+ return 0x1000;
+ }
}
/* return the size of a pointer on the target CPU */
@@ -1050,6 +1064,7 @@ unsigned int get_ptr_size(void)
case CPU_ARM:
return 4;
case CPU_x86_64:
+ case CPU_POWERPC64:
case CPU_ARM64:
return 8;
}
--
2.25.1
More information about the wine-devel
mailing list