Alexandre Julliard : winebuild: Generate Thumb2-compatible assembly code on ARM.

Alexandre Julliard julliard at winehq.org
Tue Jan 19 15:44:00 CST 2021


Module: wine
Branch: master
Commit: c1a700f018ae86b31c61b0ce4e932f335a6f5081
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=c1a700f018ae86b31c61b0ce4e932f335a6f5081

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Sat Jan 16 11:05:38 2021 +0100

winebuild: Generate Thumb2-compatible assembly code on ARM.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 tools/winebuild/import.c | 58 ++++++++++++++++++++++++------------------------
 tools/winebuild/main.c   |  2 ++
 tools/winebuild/spec32.c |  8 ++++---
 tools/winebuild/utils.c  | 11 ++++++++-
 4 files changed, 46 insertions(+), 33 deletions(-)

diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c
index e6dff564f79..00b6f19ec98 100644
--- a/tools/winebuild/import.c
+++ b/tools/winebuild/import.c
@@ -755,9 +755,10 @@ static void output_import_thunk( const char *name, const char *table, int pos )
         output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
         break;
     case CPU_ARM:
-        output( "\tldr IP,1f\n");
-        output( "\tldr PC,[PC,IP]\n" );
-        output( "1:\t.long %s+%u-(1b+4)\n", table, pos );
+        output( "\tldr ip, 2f\n");
+        output( "1:\tadd ip, pc\n" );
+        output( "\tldr pc, [ip]\n");
+        output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
         break;
     case CPU_ARM64:
         output( "\tadrp x16, %s\n", arm64_page( table ) );
@@ -956,7 +957,7 @@ static void output_delayed_imports( const DLLSPEC *spec )
             struct import_func *func = &import->imports[j];
             const char *name = func->name ? func->name : func->export_name;
             output( "__imp_%s:\n", asm_name( name ));
-            output( "\t%s .L__wine_delay_imp_%s_%s\n",
+            output( "\t%s __wine_delay_imp_%s_%s\n",
                     get_asm_ptr_keyword(), import->c_name, name );
         }
     }
@@ -1066,13 +1067,10 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
     case CPU_ARM:
         output( "\tpush {r0-r3,FP,LR}\n" );
         output( "\tmov r0,IP\n" );
-        output( "\tldr IP,2f\n");
-        output( "\tadd IP,PC\n");
-        output( "\tblx IP\n");
-        output( "1:\tmov IP,r0\n");
+        output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
+        output( "\tmov IP,r0\n");
         output( "\tpop {r0-r3,FP,LR}\n" );
         output( "\tbx IP\n");
-        output( "2:\t.long %s-1b\n", asm_name("__wine_spec_delay_load") );
         break;
     case CPU_ARM64:
         output( "\tstp x29, x30, [sp,#-80]!\n" );
@@ -1153,7 +1151,8 @@ static void output_delayed_import_thunks( const DLLSPEC *spec )
             struct import_func *func = &import->imports[j];
             const char *name = func->name ? func->name : func->export_name;
 
-            output( ".L__wine_delay_imp_%s_%s:\n", import->c_name, name );
+            if (thumb_mode) output( "\t.thumb_func\n" );
+            output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
             output_cfi( ".cfi_startproc" );
             switch(target_cpu)
             {
@@ -1349,14 +1348,13 @@ void output_stubs( DLLSPEC *spec )
             output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
             break;
         case CPU_ARM:
-            output( "\tldr r0,2f\n");
-            output( "\tadd r0,PC\n");
-            output( "\tldr r1,2f+4\n");
-            output( "1:" );
-            if (exp_name) output( "\tadd r1,PC\n");
+            output( "\tldr r0,3f\n");
+            output( "1:\tadd r0,PC\n");
+            output( "\tldr r1,3f+4\n");
+            if (exp_name) output( "2:\tadd r1,PC\n");
             output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
-            output( "2:\t.long .L__wine_spec_file_name-1b\n" );
-            if (exp_name) output( "\t.long .L%s_string-2b\n", name );
+            output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
+            if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
             else output( "\t.long %u\n", odp->ordinal );
             break;
         case CPU_ARM64:
@@ -1566,28 +1564,30 @@ void output_syscalls( DLLSPEC *spec )
             output( "\tstr ip, [sp, #4]\n" );
             output( "\tstr sp, [r7]\n" );  /* syscall frame */
             output( "\tldr r5, 7f\n");
-            output( "\tadd r5, pc\n");
+            output( "1:\tadd r5, pc\n");
             output( "\tldrb r5, [r5, r4]\n" );  /* syscall args */
-            output( "1:\tsubs r5, #16\n" );   /* first 4 args are in registers */
+            output( "\tsubs r5, #16\n" );   /* first 4 args are in registers */
             output( "\tble 3f\n" );
-            output( "\tsub sp, r5\n" );
-            output( "\tand sp, #~7\n" );
+            output( "\tsub ip, sp, r5\n" );
+            output( "\tand ip, #~7\n" );
+            output( "\tmov sp, ip\n" );
             output( "2:\tsubs r5, r5, #4\n" );
             output( "\tldr ip, [r6, r5]\n" );
             output( "\tstr ip, [sp, r5]\n" );
             output( "\tbgt 2b\n" );
             output( "3:\tldr r5, 6f\n");
-            output( "\tadd r5, pc\n");
+            output( "4:\tadd r5, pc\n");
             output( "\tldr ip, [r5, r4, lsl #2]\n");  /* syscall table */
-            output( "4:\tblx ip\n");
+            output( "\tblx ip\n");
             output( "\tmov ip, #0\n" );
             output( "\tstr ip, [r7]\n" );
-            output( "\tsub sp, r6, #40\n" );
+            output( "\tsub ip, r6, #40\n" );
+            output( "\tmov sp, ip\n" );
             output( "\tpop {r5-r11,pc}\n" );
             output( "5:\tldr r0, 9f\n" );
             output( "\tpop {r5-r11,pc}\n" );
-            output( "6:\t.long .Lsyscall_table-4b\n" );
-            output( "7:\t.long .Lsyscall_args-1b\n" );
+            output( "6:\t.long .Lsyscall_table-4b-%u\n", thumb_mode ? 4 : 8 );
+            output( "7:\t.long .Lsyscall_args-1b-%u\n", thumb_mode ? 4 : 8 );
             output( "8:\t.long %u\n", count );
             output( "9:\t.long 0x%x\n", invalid_param );
             break;
@@ -1731,11 +1731,11 @@ void output_syscalls( DLLSPEC *spec )
             output( "\tpush {r4,lr}\n" );
             output( "\tldr r4, 3f\n");
             output( "\tldr ip, 2f\n");
-            output( "\tadd ip, pc\n");
+            output( "1:\tadd ip, pc\n" );
             output( "\tldr ip, [ip]\n");
-            output( "1:\tblx ip\n");
+            output( "\tblx ip\n");
             output( "\tpop {r4,pc}\n" );
-            output( "2:\t.long %s-1b\n", asm_name("__wine_syscall_dispatcher") );
+            output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
             output( "3:\t.long %u\n", i );
             break;
         case CPU_ARM64:
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c
index 572b4d74ae7..abb94e27c03 100644
--- a/tools/winebuild/main.c
+++ b/tools/winebuild/main.c
@@ -244,6 +244,8 @@ static void set_target( const char *target )
     }
 
     free( spec );
+
+    if (target_cpu == CPU_ARM && target_platform == PLATFORM_WINDOWS) thumb_mode = 1;
 }
 
 /* cleanup on program exit */
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c
index a12e7d38aac..6d56cc01b6e 100644
--- a/tools/winebuild/spec32.c
+++ b/tools/winebuild/spec32.c
@@ -249,6 +249,7 @@ static void output_relay_debug( DLLSPEC *spec )
     /* then the relay thunks */
 
     output( "\t.text\n" );
+    if (thumb_mode) output( "\t.thumb_func\n" );
     output( "__wine_spec_relay_entry_points:\n" );
     output( "\tnop\n" );  /* to avoid 0 offset */
 
@@ -306,6 +307,7 @@ static void output_relay_debug( DLLSPEC *spec )
 
             val = (odp->u.func.args_str_offset << 16) | (i - spec->base);
             output( "\t.align %d\n", get_alignment(4) );
+            if (thumb_mode) output( "\t.thumb_func\n" );
             output( ".L__wine_spec_relay_entry_point_%d:\n", i );
             output_cfi( ".cfi_startproc" );
             output( "\tpush {r0-r3}\n" );
@@ -317,13 +319,13 @@ static void output_relay_debug( DLLSPEC *spec )
                 if (val & mask) output( "\t%s r1,#%u\n", count++ ? "add" : "mov", val & mask );
             if (!count) output( "\tmov r1,#0\n" );
             output( "\tldr r0, 2f\n");
-            output( "\tadd r0, PC\n");
+            output( "1:\tadd r0, PC\n");
             output( "\tldr IP, [r0, #4]\n");
-            output( "1:\tblx IP\n");
+            output( "\tblx IP\n");
             output( "\tldr IP, [SP, #4]\n" );
             output( "\tadd SP, #%u\n", 24 + (has_float ? 64 : 0) );
             output( "\tbx IP\n");
-            output( "2:\t.long .L__wine_spec_relay_descr-1b\n" );
+            output( "2:\t.long .L__wine_spec_relay_descr-1b-%u\n", thumb_mode ? 4 : 8 );
             output_cfi( ".cfi_endproc" );
             break;
         }
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c
index 5cffc74accd..1a11d275cb3 100644
--- a/tools/winebuild/utils.c
+++ b/tools/winebuild/utils.c
@@ -690,6 +690,11 @@ void output_standard_file_header(void)
         output( "\t.globl  @feat.00\n" );
         output( ".set @feat.00, 1\n" );
     }
+    if (thumb_mode)
+    {
+        output( "\t.syntax unified\n" );
+        output( "\t.thumb\n" );
+    }
 }
 
 /* dump a byte stream into the assembly code */
@@ -1119,13 +1124,17 @@ const char *func_declaration( const char *func )
         return "";
     case PLATFORM_WINDOWS:
         free( buffer );
-        buffer = strmake( ".def %s\n\t.scl 2\n\t.type 32\n\t.endef", asm_name(func) );
+        buffer = strmake( ".def %s\n\t.scl 2\n\t.type 32\n\t.endef%s", asm_name(func),
+                          thumb_mode ? "\n\t.thumb_func" : "" );
         break;
     default:
         free( buffer );
         switch(target_cpu)
         {
         case CPU_ARM:
+            buffer = strmake( ".type %s,%%function%s", func,
+                              thumb_mode ? "\n\t.thumb_func" : "" );
+            break;
         case CPU_ARM64:
             buffer = strmake( ".type %s,%%function", func );
             break;




More information about the wine-cvs mailing list