[Bug 30134] 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)

wine-bugs at winehq.org wine-bugs at winehq.org
Sat Mar 10 19:14:53 CST 2012


http://bugs.winehq.org/show_bug.cgi?id=30134

--- Comment #1 from Anastasius Focht <focht at 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/6f84e89d2dbb7fb18e921fa82782d200a242880b:/tools/winebuild/spec32.c#l431

--- 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

-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list