http://bugs.winehq.org/show_bug.cgi?id=30134
Bug #: 30134 Summary: Wine on ARM: .init/.text sections passed to assembler need directives to allow for mixed/pure arm32/thumb2 builds (.init section thumb2 libc ctors vs. Wine arm32 ctor) Product: Wine Version: 1.4 Platform: arm OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: tools AssignedTo: wine-bugs@winehq.org ReportedBy: focht@gmx.net Classification: Unclassified
Hello,
Wine on ARM - some food ;-) I have some ARM machines "pets" at home, ranging from low spec ARM7TDMI (ARMv4T) to Cortex-A8 (ARMv7-A) and Cortex-A9 MPCore dual and quad flavours - currently considered high spec - until Cortex-A15 shows up.
The dual/quad Cortex-A9 machines which I use for work/development are running recent 3.1/3.2 Linux kernels and distros, mostly based on Linaro builds. Good enough to build Wine with decent speed - slower than i3/i5 multicore but comparable to my Atom-based machines. The difference: 3 watts (quad core A9) vs. 35 watts (dual core Atom with 4 hyperthreads) under full load (idle load ratio is even worse).
Linaro toolchains are used to build Wine, they have a default profile for Cortex-A9 Thumb-2 NEON (CFLAGS="-gdwarf-2" was passed to Wine).
--- snip --- $ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabi/4.6.1/lto-wrapper Target: arm-linux-gnueabi Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.6.1-9ubuntu3' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-plugin --enable-objc-gc --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-float=softfp --with-fpu=vfpv3-d16 --with-mode=thumb --disable-werror --enable-checking=release --build=arm-linux-gnueabi --host=arm-linux-gnueabi --target=arm-linux-gnueabi Thread model: posix gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3) ... $ as -v GNU assembler version 2.21.53 (arm-linux-gnueabi) using BFD version (GNU Binutils for Ubuntu) 2.21.53.20110810 --- snip ---
Running "wineboot" to create a fresh WINEPREFIX gives:
--- snip --- $ wineboot wine: created the configuration directory '/home/linaro/.wine' fixme:seh:RtlUnwind Not implemented on ARM err:module:attach_process_dlls "ntdll.dll" failed to initialize, aborting err:seh:segv_handler Got unexpected trap 0 fixme:seh:RtlUnwind Not implemented on ARM err:module:attach_process_dlls "ntdll.dll" failed to initialize, aborting err:seh:segv_handler Got unexpected trap 0 Segmentation fault --- snip ---
Gdb session:
--- snip --- $ gdb wine GNU gdb (Ubuntu/Linaro 7.3-0ubuntu2) 7.3-2011.08 ... (gdb) run wineboot Starting program: /home/linaro/projects/wine/wine-install/bin/wine wineboot [Thread debugging using libthread_db enabled] fixme:seh:RtlUnwind Not implemented on ARM err:module:attach_process_dlls "ntdll.dll" failed to initialize, aborting err:seh:segv_handler Got unexpected trap 0
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 0x4027182a in _init () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so #2 0x402de0e6 in __wine_spec_dll_entry (inst=Cannot access memory at address 0xbf2903cb ) at /home/linaro/projects/wine/wine-git/dlls/winecrt0/dll_entry.c:37 Cannot access memory at address 0xbf2903db ... (gdb) info reg r0 0x1 1 r1 0x407d4380 1081951104 r2 0x354 852 r3 0x0 0 r4 0xbeffe2d0 3204440784 r5 0xbeffed70 3204443504 r6 0x88c1 35009 r7 0xbf2903bf 3207136191 r8 0x0 0 r9 0x0 0 r10 0x4001e000 1073864704 r11 0x0 0 r12 0x402f6328 1076847400 sp 0x40d6fc38 0x40d6fc38 lr 0x4027182b 1076303915 pc 0x40280000 0x40280000 <__wine_spec_pe_header+59344> cpsr 0xf0030 983088 --- snip ---
cpsr "T" bit is set so we are in thumb mode.
Disassembly of ".init" section shows thumb2 code due to toolchain defaults.
--- snip --- (gdb) disas 0x4027182a Dump of assembler code for function _init: 0x40271824 <+0>: push {r3, lr} 0x40271826 <+2>: bl 0x402831c0 <call_gmon_start> 0x4027182a <+6>: nop 0x4027182c <+8>: b 0x40282830 <__wine_spec_pe_header+69632> __wine_spec_pe_header: ... 0x40d88604 <+69628>: andeq r0, r0, r0 0x40d88608 <+69632>: blx 0x40db3eac <__wine_spec_init_ctor> 0x40d8860c <+69636>: pop {r3, pc} --- snip ---
The long branch at 0x4027182c (part of .init section that belongs to Wine) was assembled as 32 bit ARM code because GNU assembler will generate 32 bit ARM code by default if not told otherwise (Wine doesn't explicitly emit directives for sections nor passes additional options to "as")
Before and after entering "call_gmon_start" it was thumb mode, hence no veneer required to do a mode switch (thumb <-> arm).
--- snip --- $ ls -la /usr/lib/*/crt* -rw-r--r-- 1 root root 1588 2012-03-07 05:21 /usr/lib/arm-linux-gnueabi/crt1.o -rw-r--r-- 1 root root 1216 2012-03-07 05:21 /usr/lib/arm-linux-gnueabi/crti.o -rw-r--r-- 1 root root 884 2012-03-07 05:21 /usr/lib/arm-linux-gnueabi/crtn.o -rw-r--r-- 1 root root 1588 2012-03-07 05:26 /usr/lib/arm-linux-gnueabihf/crt1.o -rw-r--r-- 1 root root 1216 2012-03-07 05:26 /usr/lib/arm-linux-gnueabihf/crti.o -rw-r--r-- 1 root root 884 2012-03-07 05:26 /usr/lib/arm-linux-gnueabihf/crtn.o --- snip ---
--- snip --- $ objdump -x /usr/lib/arm-linux-gnueabi/crti.o
/usr/lib/arm-linux-gnueabi/crti.o: file format elf32-littlearm /usr/lib/arm-linux-gnueabi/crti.o architecture: arm, flags 0x00000011: HAS_RELOC, HAS_SYMS start address 0x00000000 private flags = 5000000: [Version5 EABI] ... RELOCATION RECORDS FOR [.text]: OFFSET TYPE VALUE 0000000a R_ARM_THM_JUMP24 __gmon_start__ 00000010 R_ARM_GOTPC _GLOBAL_OFFSET_TABLE_ 00000014 R_ARM_GOT32 __gmon_start__
RELOCATION RECORDS FOR [.init]: OFFSET TYPE VALUE 00000002 R_ARM_THM_CALL call_gmon_start --- snip ---
"call_gmon_start" code from libc's initfini, obviously thumb/thumb2:
--- snip --- $ objdump -d /usr/lib/arm-linux-gnueabi/crti.o
/usr/lib/arm-linux-gnueabi/crti.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <call_gmon_start>: 0: 4b03 ldr r3, [pc, #12] ; (10 <call_gmon_start+0x10>) 2: 4a04 ldr r2, [pc, #16] ; (14 <call_gmon_start+0x14>) 4: 447b add r3, pc 6: 589b ldr r3, [r3, r2] 8: b10b cbz r3, e <call_gmon_start+0xe> a: f7ff bffe b.w 0 <__gmon_start__> e: 4770 bx lr 10: 00000008 .word 0x00000008 14: 00000000 .word 0x00000000
Disassembly of section .init:
00000000 <_init>: 0: b508 push {r3, lr} 2: f7ff fffe bl 0 <_init> 6: bf00 nop
Disassembly of section .fini:
00000000 <_fini>: 0: b508 push {r3, lr} 2: bf00 nop --- snip ---
--- snip --- (gdb) disas Dump of assembler code for function call_gmon_start: 0x402831c0 <+0>: ldr r3, [pc, #12] ; (0x402831d0 <call_gmon_start+16>) 0x402831c2 <+2>: ldr r2, [pc, #16] ; (0x402831d4 <call_gmon_start+20>) 0x402831c4 <+4>: add r3, pc 0x402831c6 <+6>: ldr r3, [r3, r2] 0x402831c8 <+8>: cbz r3, 0x402831ce <call_gmon_start+14> 0x402831ca <+10>: b.w 0x40282cc4 => 0x402831ce <+14>: bx lr 0x402831d0 <+16>: andeq r2, r7, r8, lsr lr 0x402831d4 <+20>: andeq r0, r0, r4, asr r3 End of assembler dump. (gdb) info reg r0 0x1 1 r1 0x407d4380 1081951104 r2 0x354 852 r3 0x0 0 r4 0xbeffe2d0 3204440784 r5 0xbeffed70 3204443504 r6 0x88c1 35009 r7 0x40d6fc40 1087831104 r8 0x0 0 r9 0x0 0 r10 0x4001e000 1073864704 r11 0x0 0 r12 0x402f6328 1076847400 sp 0x40d6fc38 0x40d6fc38 lr 0x4027182b 1076303915 pc 0x402831ce 0x402831ce <call_gmon_start+14> cpsr 0x800f0030 -2146500560 --- snip ---
"bx lr" (return from subroutine): due to cpsr "T" bit already set, it will remain in thumb mode.
--- snip --- (gdb) si 0x4027182a in _init () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so (gdb) disas Dump of assembler code for function _init: 0x40271824 <+0>: push {r3, lr} 0x40271826 <+2>: bl 0x402831c0 <call_gmon_start> => 0x4027182a <+6>: nop 0x4027182c <+8>: b 0x40282830 <__wine_spec_pe_header+69632> End of assembler dump. (gdb) info reg r0 0x1 1 r1 0x407d4380 1081951104 r2 0x354 852 r3 0x0 0 r4 0xbeffe2d0 3204440784 r5 0xbeffed70 3204443504 r6 0x88c1 35009 r7 0x40d6fc40 1087831104 r8 0x0 0 r9 0x0 0 r10 0x4001e000 1073864704 r11 0x0 0 r12 0x402f6328 1076847400 sp 0x40d6fc38 0x40d6fc38 lr 0x4027182b 1076303915 pc 0x4027182a 0x4027182a <_init+6> cpsr 0x800f0030 -2146500560 --- snip ---
Still in thumb mode (16 bit nop). The next long branch was originally assembled s 32 bit ARM opcode (through Wine's assembler invocation) and is not valid for thumb mode.
--- snip --- (gdb) disas Dump of assembler code for function _init: 0x40271824 <+0>: push {r3, lr} 0x40271826 <+2>: bl 0x402831c0 <call_gmon_start> 0x4027182a <+6>: nop => 0x4027182c <+8>: b 0x40282830 <__wine_spec_pe_header+69632> End of assembler dump. (gdb) si 0x4027182e in _init () from /home/linaro/projects/wine/wine-install/bin/../lib/wine/ntdll.dll.so --- snip ---
It's interpreted as two distinct 16 bit thumb opcodes, hence not doing as intended (branch over 64 KiB).
Regards