https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80759

--- Comment #50 from Daniel Santos <daniel.santos at pobox dot com> ---
Created attachment 41605
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=41605&action=edit
darwin fixup (on top of v6)

(In reply to r...@cebitec.uni-bielefeld.de from comment #49)
> 
> No worries at all: don't even think about this stuff before you're well
> again!

Thank you, but this is chronic and comes and goes.  The trend line seems to be
heading upward for the moment, however.

>[...]
> > In hopes of making your review easier, below is a delta between this new 
> > (v6)
> > patch set and your last posted patches.
> 
> The new patch works fine for me on both x86_64-pc-linux-gnu (as
> expected) and i386-pc-solaris2.12.
> 
> On x86_64-apple-darwin11.4.2, there are a couple of isues, some of which
> I'd already resolved before you posted the revised patch.
> 
> * Initially all tests SEGVed like this (e.g. with -p0 and compiled with -O2):
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0x000000010004664d in regs_to_mem ()
> 1: x/i $pc
> => 0x10004664d <regs_to_mem>:   movaps %xmm6,(%rax)
> (gdb) where
> #0  0x000000010004664d in regs_to_mem ()
> #1  0x00000001000465df in do_test_body ()
> #2  0x000000010002f227 in do_tests_0000 ()
> #3  0x00000001000468e3 in main ()
> 
>   Here, %rax is 0x0.
> 
>   This happens because some setup happens between do_test_body0 and
>   do_test_body, and do_test_aligned jumps directly to do_test_body:
> 
>         .globl _do_test_body0
>         .no_dead_strip _do_test_body0
> _do_test_body0:
>         movq    _test_data@GOTPCREL(%rip), %rax
> 
>         .globl _do_test_body
> _do_test_body:
> 
>         # Save registers.
>         lea     (%rax), %rax
>         call    _regs_to_mem
> 
>   By that jump, you bypass the setup of %rax and make the test FAIL.  I
>   managed to avoid this by changing the jmp to do_test_body0 instead.
>   This gets me past this failure, and works on Linux/x86_64, too.
>   However, this makes the tests FAIL on Solaris/x86, supposedly due to
>   the -fomit-frame-pointer/-fno-omit-frame-pointer difference (though I
>   haven't looked more closely).

Thanks again for your help on this.  All of this asm is a big ABI hack and
presumes I'm working with 64-bit SystemV ABI, but apple's ABI appears to differ
somewhat (I've may have found a good description of that here:
https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/MachOTopics/1-Articles/x86_64_code.html).

My hope in declaring my own global symbol in the assembly and then explicitly
RET-ing was to bypass any ABI-specific setup and tear-down, most notably the
hard frame pointer.  In the case of Darwin, this doesn't appear to work since
the asm template instantiation of my "global + offset" seems to work quite
differently and wants to store the base address in a register that is already
being used for something else (actually, every register except XMM0-5 and
XMM16+ are volatile at this point).  I had expected it to generate something
akin to:

        lea test_data + 224(%rip), %rax

It would be nice if the "naked" function attribute were available for the i386
back-end, then I wouldn't have to screw around with trying to hack-away the
ABI. (maybe a worthwhile future venture)

The attached patch (on top of v6) *might* solve the problem on Darwin, but I
don't understand exactly how GOTPCREL works, other than it's using a global
offset table for linking.  Hopefully, the linker can translate this directly
into a constant rip-rel offset.  What I'm doing here is that instead of feeding
addresses to the asm template, I'm giving in the offsets and schlepping
together an address operand from that, e.g.:

        lea %p0 + test_data@GOTPCREL(%%rip), %%rax

Now if this fix *does* work, then I might need to investigate if this is a
performance problem for Darwin -- why use an extra instruction to copy the
address to a register before modifying it?  If it doesn't work then it's
probably because it really *needs* two instructions.  I'm curious what the
disassembly of the linked program looks like.

> 
> * With the do_test_body0 jump, I hit the next issue on Darwin with -O0:
>   the test SEGVs here:
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0x0000000100031c4e in do_test_body0 ()
>     at
> /vol/gcc/src/hg/trunk/solaris/gcc/testsuite/gcc.target/x86_64/abi/ms-sysv/ms-
> sysv.c:163
> 163       __asm__ ("\n"
> 1: x/i $pc
> => 0x100031c4e <do_test_body0+21>:      mov    %rax,0x2a8(%rdi)
> (gdb) where
> (gdb) p/x $rdi
> $1 = 0x5dc3340b214ef45c

Yeah, this won't work because the reality is that all GP registers are volatile
at this point, but gcc will generate code that clobbers them based upon the
alleged ABI of the function -- which is a lie. :)  If the attached patch
doesn't work, then I think it's best to just move the assembly back into
do-test.S and hard-code the offsets in a shared header file, so we can use them
as a macro from do-test.S and also check them with asserts in ms-sysv.c.

I suppose another option would be to just declare everything as clobbered in
the asm clobber list, but that somehow just makes me feel dirty. :)

Thanks,
Daniel

Reply via email to