Module: wine Branch: master Commit: 9e9509f3074b9170f5acd432067f8a9b1b599eca URL: https://source.winehq.org/git/wine.git/?a=commit;h=9e9509f3074b9170f5acd4320...
Author: Martin Storsjö martin@martin.st Date: Wed Nov 3 14:41:36 2021 +0200
winebuild: Fix relay entry points in Thumb mode with binutils/ELF and LLVM/PE.
b1fe783adee51b5c3d3c0dc58e5dc1e81fd46299 fixed relay entry points in Thumb mode when assembled with Clang/LLVM in ELF mode, but broke them when assembled with binutils as (and PE mode with LLVM didn't work either before or after).
When/where the thumb bit is applied on symbols varies a lot between assemblers; this is a notoriously vague and undocumented area.
After a .thumb_func directive, binutils as considers the next non-local symbol as a thumb symbol, to have the thumb bit set. LLVM's built-in assembler considers the next symbol, local or not, to be a thumb symbol. (Just noting for reference for possible solutions, this particular difference didn't play a role so far.)
Secondly, in a symbol difference expression like this:
.long symbol1 - symbol2
Binutils as ignores the potential thumb state for both symbols and just calculates the raw distance. LLVM does include the thumb bit in symbol1 but ignores it in symbol2.
Finally, for PE targets, the linker sets the thumb bit on all absolute addresses pointing to the text section, regardless of any .thumb_func directives at assembly time. (I.e., the __wine_spec_relay_entry_points entry in .L__wine_spec_relay_descr gets the bit set even if it wasn't marked as .thumb_func.)
Therefore, mark __wine_spec_relay_entry_points as .thumb_func, as the absolute address to it will end up with the thumb bit set in PE builds in any case.
Don't mark the individual relay entry pointers as thumb functions (the code still is generated as thumb as there hasn't been any mode switch back to arm mode); this makes the differences calculated correctly (both LLVM and binutils ignore the thumb state of the subtracted label).
If desired, one could change __wine_spec_relay_entry_point_%d into local labels with a .L prefix, just as before b1fe783adee51b5c3d3c0dc58e5dc1e81fd46299 again, it doesn't make any difference in this form.
Signed-off-by: Martin Storsjö martin@martin.st Signed-off-by: Alexandre Julliard julliard@winehq.org
---
tools/winebuild/spec32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 513778ad10c..36df296b9c1 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -248,6 +248,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 */
@@ -303,7 +304,6 @@ static void output_relay_debug( DLLSPEC *spec ) has_float = is_float_arg( odp, j );
output( "\t.align %d\n", get_alignment(4) ); - if (thumb_mode) output( "\t.thumb_func\n" ); output( "__wine_spec_relay_entry_point_%d:\n", i ); output_cfi( ".cfi_startproc" ); output( "\tpush {r0-r3}\n" );