http://bugs.winehq.org/show_bug.cgi?id=30134
--- Comment #1 from Anastasius Focht focht@gmx.net 2012-03-10 19:14:53 CST --- Hello,
for good overview/porting guide regarding thumb2 see:
https://wiki.edubuntu.org/ARM/Thumb2PortingHowto
Back to the problem ...
If I force 32 bit ARM code generation through the build system, passing "-marm" to compiler CFLAGS, overriding compiler's default "-mthumb" it won't work here.
Looking at the intermediate assembler file (-save-temps):
--- snip --- /* File generated automatically from /home/linaro/projects/wine/wine-git/dlls/ntdll/ntdll.spec; do not edit! */ /* This file can be copied, modified and distributed without restriction. */
.section ".init","ax"
b 1f __wine_spec_pe_header: .skip 69632 1:
.data .align 2 .globl __wine_spec_nt_header .hidden __wine_spec_nt_header __wine_spec_nt_header: .L__wine_spec_rva_base: .long 0x4550 ... .long 0,0
.section .rodata .globl __wine_spec_file_name .hidden __wine_spec_file_name __wine_spec_file_name: .L__wine_spec_file_name: .string "ntdll.dll"
.section ".init","ax" bl __wine_spec_init_ctor --- snip ---
There is no explicit ".arm" (.code 32) or ".thumb" (.code 16) directive for the sections. As already said: the GNU assembler will generate 32 bit ARM object code from .s file by default if not told otherwise.
Due to the way the toolchain and userland was built (armv7 thumb2), userland libraries such as libc and the compiler support libraries such as libgcc will still contain thumb-2 instructions even if the compiler was invoked with "-marm".
Running "wineboot" again built with CFLAGS="-marm":
--- snip --- Program received signal SIGSEGV, Segmentation fault. 0x40280000 in __wine_spec_pe_header () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so (gdb) bt #0 0x40280000 in __wine_spec_pe_header () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so #1 0x4027682a in _init () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so #2 0x4030ceb0 in __wine_spec_dll_entry (inst=0x40280000, reason=1, reserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/winecrt0/dll_entry.c:37 #3 0x402b9154 in call_dll_entry_point (proc=0x4030ce38 <__wine_spec_dll_entry>, module=0x40280000, reason=1, reserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:175 #4 0x402bba94 in MODULE_InitDLL (wm=0x40803158, reason=1, lpReserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:978 #5 0x402bbf2c in process_attach (wm=0x40803158, lpReserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:1067 #6 0x402bbeb0 in process_attach (wm=0x40803200, lpReserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:1059 #7 0x402bbeb0 in process_attach (wm=0x408035e8, lpReserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:1059 #8 0x402bbeb0 in process_attach (wm=0x40803698, lpReserved=0x1) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:1059 #9 0x402c0ca8 in attach_process_dlls (wm=0x40803698) at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:2541 #10 0x40028e4c in wine_call_on_stack () at /home/linaro/projects/wine/wine-git/libs/wine/port.c:60 #11 0x40028e4c in wine_call_on_stack () at /home/linaro/projects/wine/wine-git/libs/wine/port.c:60 --- snip ---
Whoops.
If we now look at disassembly:
--- snip --- (gdb) disas Dump of assembler code for function __wine_spec_dll_entry: 0x4030ce38 <+0>: push {r11, lr} 0x4030ce3c <+4>: add r11, sp, #4 0x4030ce40 <+8>: sub sp, sp, #24 ... 0x4030cea0 <+104>: mov r0, r2 0x4030cea4 <+108>: mov r1, r3 0x4030cea8 <+112>: mov r2, #0 0x4030ceac <+116>: bl 0x4030e250 <___init_veneer> 0x4030ceb0 <+120>: ldr r0, [r11, #-16] 0x4030ceb4 <+124>: ldr r1, [r11, #-20] 0x4030ceb8 <+128>: ldr r2, [r11, #-24] 0x4030cebc <+132>: bl 0x402c19a4 <DllMain> 0x4030cec0 <+136>: str r0, [r11, #-8] --- snip ---
32 bit ARM code with thumb interworking veneers. The veneers are necessary because libc/libgcc is still thumb2 code, hence it needs mode switching.
The veneer will do the arm->thumb mode switch:
--- snip --- => 0x4030e250 <+0>: ldr r12, [pc, #4] ; 0x4030e25c <___init_veneer+12> 0x4030e254 <+4>: add r12, pc, r12 0x4030e258 <+8>: bx r12 0x4030e25c <+12>: ; <UNDEFINED> instruction: 0xfff685c9 ... (gdb) disas 0x40276825 Dump of assembler code for function _init: 0x40276824 <+0>: push {r3, lr} 0x40276826 <+2>: bl 0x402881c0 <call_gmon_start> 0x4027682a <+6>: nop 0x4027682c <+8>: b 0x40287830 <__wine_spec_pe_header+69632> --- snip ---
To fix the ".init" section problem for "thumb" toolchains/userlands there are several approaches.
One is to explicitly insert ".thumb" directive to ".init" section (along with ".syntax unified" to use unified assembler syntax).
Unfortunately this will break some stuff.
http://source.winehq.org/git/wine.git/blob/6f84e89d2dbb7fb18e921fa82782d200a...
--- snip --- 451 default: 452 output( "\n\t.section ".init","ax"\n" ); ... 465 output( "__wine_spec_pe_header:\n" ); 466 output( "\t.skip %u\n", 65536 + page_size ); 467 output( "1:\n" ); --- snip ---
"b 1f" -> 16-bit thumb branch can't encode the range required by __wine_spec_pe_header padding (64 KiB).
If you are on armv6t2+ machines (like Cortex-A series) you can use thumb2 long branch here. The 32-bit thumb2 long branch encoding has a range of +/-16MiB,
--- snip --- .syntax unified .thumb b.w 1f ... 1: --- snip ---
For machines < armv6t2 (no thumb2 support) you have to encode the long branch differently, ex:
--- snip --- add r12, pc, #5 add r12, r12, #69632 ; 0x11000 bx r12 --- snip ---
It might be useful to separate the current shared code snippets between CPU_ARM and CPU_POWERPC to allow handling of ARM-specifics better. This is also needed for proper insertion of section attributes for assembler.
Defining ".init" as ".thumb" and inserting proper thumb(2) branch, "wineboot" still fails:
--- snip --- Program received signal SIGSEGV, Segmentation fault. 0x40931b40 in NtCurrentTeb () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/kernel32.dll.so (gdb) bt #0 0x40931b40 in NtCurrentTeb () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/kernel32.dll.so #1 0x4097666c in __wine_kernel_init () at /home/linaro/projects/wine/wine-git/dlls/kernel32/process.c:1138 #2 0x402c1d1c in __wine_process_init () at /home/linaro/projects/wine/wine-git/dlls/ntdll/loader.c:2877 #3 0x40026ff8 in wine_init (argc=2, argv=0xbefff764, error=0xbefff20c "", error_size=1024) at /home/linaro/projects/wine/wine-git/libs/wine/loader.c:831 #4 0x00008bbc in main (argc=2, argv=0xbefff764) at /home/linaro/projects/wine/wine-git/loader/main.c:230 --- snip ---
Whoops.
--- snip --- (gdb) disas 0x4097666c Dump of assembler code for function __wine_kernel_init: 0x40976640 <+0>: push {r4, r5, r11, lr} 0x40976644 <+4>: add r11, sp, #12 0x40976648 <+8>: sub sp, sp, #3680 ; 0xe60 0x4097664c <+12>: sub sp, sp, #8 0x40976650 <+16>: ldr r4, [pc, #1916] ; 0x40976dd4 <__wine_kernel_init+1940> 0x40976654 <+20>: add r4, pc, r4 0x40976658 <+24>: ldr r3, [pc, #1912] ; 0x40976dd8 <__wine_kernel_init+1944> 0x4097665c <+28>: ldr r3, [r4, r3] 0x40976660 <+32>: ldr r3, [r3] 0x40976664 <+36>: str r3, [r11, #-16] 0x40976668 <+40>: bl 0x409a06d8 <__NtCurrentTeb_veneer> 0x4097666c <+44>: mov r3, r0 ... (gdb) disas 0x409a06d8 Dump of assembler code for function __NtCurrentTeb_veneer: 0x409a06d8 <+0>: ldr r12, [pc, #4] ; 0x409a06e4 <__NtCurrentTeb_veneer+12> 0x409a06dc <+4>: add r12, pc, r12 0x409a06e0 <+8>: bx r12 0x409a06e4 <+12>: ; <UNDEFINED> instruction: 0xfff91459 End of assembler dump. ... (gdb) disas NtCurrentTeb Dump of assembler code for function NtCurrentTeb: 0x402ef578 <+0>: push {r11, lr} 0x402ef57c <+4>: add r11, sp, #4 0x402ef580 <+8>: ldr r3, [pc, #24] ; 0x402ef5a0 <NtCurrentTeb+40> 0x402ef584 <+12>: add r3, pc, r3 0x402ef588 <+16>: ldr r3, [r3] 0x402ef58c <+20>: mov r0, r3 0x402ef590 <+24>: bl 0x402881b0 0x402ef594 <+28>: mov r3, r0 0x402ef598 <+32>: mov r0, r3 0x402ef59c <+36>: pop {r11, pc} --- snip ---
It seems the import thunks are now considered thumb (same .s spec file) but the actual function code was generated as separate .o with 32 bit ARM code through C compiler (-marm).
".arm" directives have to be explicitly emitted for import thunks ".text" section (output_immediate_import_thunks). Also: output_delayed_import_thunks, output_stubs (basically everything that outputs "\t.text\n" passed to assembler).
With that changes applied Wine builtin programs (wineboot, notepad) finally start in thumb2 userland (though compiled as arm32, except for .init part) ;-)
Well, it is possible to create a full thumb2 Wine build but that requires more work, emitting more section directives and revising ARM inline assembler code.
You might ask: why not rebuilding the target toolchain with "--with-mode=arm" instead of "--with-mode=thumb ..."?
The toolchain is arm-linux target hence glibc has already been compiled and provides the crti.o startup file as thumb2 (chicken and egg problem).
For arm32 crti.o startup file I would have to create a compiler for arm-elf target. I could hack arm-linux toolchain target to also include building of crti.o but that isn't really feasible ...
Regards