[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