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