Signed-off-by: André Hentschel nerv@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@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@highest\n", ppc_reg(12), asm_name("__wine_spec_delay_load") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_spec_delay_load") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(12), (idx << 16) | j ); + output( "\tori %s, %s, %d@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@high\n", ppc_reg(12), ppc_reg(12), (idx << 16) | j ); + output( "\tori %s, %s, %d@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@highest\n", ppc_reg(12), asm_name("__wine_delay_load_asm") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_delay_load_asm") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(3) ); + output( "\tori %s, %s, .L__wine_spec_file_name@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@high\n", ppc_reg(3), ppc_reg(3) ); + output( "\tori %s, %s, .L__wine_spec_file_name@l\n", ppc_reg(3), ppc_reg(3) ); + if (exp_name) + { + output( "\tlis %s, .L%s_string@highest\n", ppc_reg(4), name ); + output( "\tori %s, %s, .L%s_string@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@high\n", ppc_reg(4), ppc_reg(4), name ); + output( "\tori %s, %s, .L%s_string@l\n", ppc_reg(4), ppc_reg(4), name ); + } + else + { + output( "\tlis %s, %u@highest\n", ppc_reg(4), odp->ordinal ); + output( "\tori %s, %s, %u@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@high\n", ppc_reg(4), ppc_reg(4), odp->ordinal ); + output( "\tori %s, %s, %u@l\n", ppc_reg(4), ppc_reg(4), odp->ordinal ); + } + output( "\tlis %s, __wine_spec_unimplemented_stub@highest\n", ppc_reg(12) ); + output( "\tori %s, %s, __wine_spec_unimplemented_stub@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@high\n", ppc_reg(12), ppc_reg(12) ); + output( "\tori %s, %s, __wine_spec_unimplemented_stub@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@highest\n", ppc_reg(12), count ); + output( "\tori %s, %s, %u@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@high\n", ppc_reg(12), ppc_reg(12), count ); + output( "\tori %s, %s, %u@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@highest\n", ppc_reg(12), asm_name("NtCurrentTeb") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name("NtCurrentTeb") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(12), asm_name(".Lsyscall_args") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_args") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(12), asm_name(".Lsyscall_table") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name(".Lsyscall_table") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(3), invalid_param ); + output( "\tori %s, %s, %u@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@high\n", ppc_reg(3), ppc_reg(3), invalid_param ); + output( "\tori %s, %s, %u@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@highest\n", ppc_reg(12), asm_name("__wine_syscall_dispatcher") ); + output( "\tori %s, %s, %s@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@high\n", ppc_reg(12), ppc_reg(12), asm_name("__wine_syscall_dispatcher") ); + output( "\tori %s, %s, %s@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@highest\n", ppc_reg(11), i ); + output( "\tori %s, %s, %u@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@high\n", ppc_reg(11), ppc_reg(11), i ); + output( "\tori %s, %s, %u@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; }