Bug 68178 - [arm] Relative address expressions bind at as-time, even if symbol is weak
Summary: [arm] Relative address expressions bind at as-time, even if symbol is weak
Status: RESOLVED DUPLICATE of bug 78253
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Ramana Radhakrishnan
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2015-11-01 18:39 UTC by Rich Felker
Modified: 2024-03-26 23:55 UTC (History)
1 user (show)

See Also:
Host:
Target: arm*
Build:
Known to work: 6.4.0
Known to fail: 6.3.0
Last reconfirmed: 2015-11-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rich Felker 2015-11-01 18:39:19 UTC
This bug is almost identical to #66609 for [sh], except the conditions needed to trigger it are slightly different. Minimal test case (compile with -fPIC; -O level does not matter):

__attribute__((__weak__,__visibility__("hidden"))) void foo()
{
}

void *bar()
{
    return (void *)foo;
}

The expected output should have a relocation for foo, since the weak definition is replaceable by a strong definition from another TU. The actual output has a PC-relative constant pointing to the weak definition.

This bug seriously broke musl libc's pthread_cancel.c, where the weak version of the symbol used for updating PC upon cancellation has the wrong contract for stack state, and the strong version from arm-specific asm needs to be used.

I still question whether this issue should be fixed on the binutils side for all targets; see: https://sourceware.org/bugzilla/show_bug.cgi?id=18561
Comment 1 Richard Biener 2015-11-02 10:24:17 UTC
Confirmed.
Comment 2 Rich Felker 2015-11-02 15:46:51 UTC
FYI a workaround for this and similar bugs, for users who are unable to upgrade once it's fixed, is to always use -ffunction-sections -fdata-sections. This inhibits the assembler's "optimization" differences between symbols simply because cross-section differences are never constant.
Comment 3 Richard Earnshaw 2015-11-02 16:34:24 UTC
This is an assembler bug and it only affects ARM state (thumb2 is OK).

In Thumb2 code we get:

00000000 <foo>:
   0:   4770            bx      lr
   2:   bf00            nop

00000004 <bar>:
   4:   4801            ldr     r0, [pc, #4]    ; (c <bar+0x8>)
   6:   4478            add     r0, pc
   8:   4770            bx      lr
   a:   bf00            nop
   c:   00000002        .word   0x00000002
                        c: R_ARM_REL32  foo

While in ARM code we get:

00000000 <foo>:
   0:   e12fff1e        bx      lr

00000004 <bar>:
   4:   e59f0004        ldr     r0, [pc, #4]    ; 10 <bar+0xc>
   8:   e08f0000        add     r0, pc, r0
   c:   e12fff1e        bx      lr
  10:   fffffff0        .word   0xfffffff0
(no relocation generated).


even though the assembly output is equivalent.

(resolving as invalid because this isn't a GCC problem but a GAS problem).
Comment 4 Rich Felker 2015-11-02 16:49:47 UTC
Well the binutils side seems to think it's a GCC bug to generate relative address expressions like this; at least that's the response I got when I reported it for sh. See the binutils bug linked in the original report above:

https://sourceware.org/bugzilla/show_bug.cgi?id=18561
Comment 5 Richard Earnshaw 2015-11-02 17:17:57 UTC
This particular case is a very specific situation.

A definition of foo is guaranteed to exist (you've provided one); but it can be overridden.

The definition (due to the use of hidden) has to exist in this share library.

Given the above, we can never get to the situation where the symbol could resolve to null, nor could we ever get to the situation where the offset to the definition can't be calculated when linking the shared library.  That makes it perfectly reasonable to use a pc-relative relocation from within the literal pool to hold the offset.

It's quite possible that with a subtle change to the conditions you could end up requiring the compiler to generate another code sequence, but not in this case.
Comment 6 Richard Earnshaw 2015-11-02 17:20:12 UTC
Oh, and another point; since this is a function symbol, not a data symbol, it can't be subject to a copy relocation at run time, so even protected symbols should be acceptable here.
Comment 7 Rich Felker 2015-11-02 17:26:47 UTC
I agree that the PC-relative relocation in the literal pool is acceptable and what the compiler should be doing. However, the form of the expression the compiler puts in the assembly output does not actually generate a relocation; instead it generates a 'fixup' that the assembler resolves before generating the output object file.

I claim it's wrong for the assembler to do this, but Alan Modra claims it's right in comment 8 on binutils bug 18561. I believe a variant of Nick Clifton's patch (from comment 6) that applies to all targets should be applied, eliminating consideration of the 'strict' option to S_FORCE_RELOC for weak definitions since this 'optimization' is always wrong for weak defs. Possibly the whole 'strict' argument should be removed; the other cases where it's used may be wrong too.
Comment 8 Richard Earnshaw 2015-11-03 11:13:30 UTC
Based on the follow-up discussions, I'm re-opening this.  While I don't think it's really a GCC bug, we can work around the assembler ambiguity problems in the compiler.

To do this, legitimize_pic_address needs to not call arm_pic_static_addr() when a symbol definition is weak, even if it does bind locally.
Comment 9 Ramana Radhakrishnan 2015-11-06 23:50:44 UTC
I'm testing a patch.
Comment 10 Rich Felker 2018-09-02 21:48:26 UTC
Was this ever fixed? I've been using -ffunction-sections -fdata-sections by default for a long time now so it dropped off my radar.
Comment 11 Andrew Pinski 2024-03-26 23:55:26 UTC
Dup of bug 78253 in the end. It was fixed in GCC 6.4.0 and GCC 5.5.0.

*** This bug has been marked as a duplicate of bug 78253 ***