This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Fix assembly of Thumb pcrel LDRs against global symbols


On Wed, 2011-03-02 at 16:37 +0000, Dave Martin wrote:
> On Wed, Mar 2, 2011 at 3:18 PM, Richard Earnshaw <rearnsha@arm.com> wrote:
> >
> > On Mon, 2011-02-28 at 12:59 +0000, Richard Sandiford wrote:
> >> The PC-relative LDR instructions have no associated relocation,
> >> so even LDRs for global symbols should be resolved by the assembler.
> >> We currently handle this correctly for single-register ARM loads,
> >> but we're missing the associated relocation types for LDRD and Thumb.
> >> This leads to errors like:
> >
> > I'm not sure I agree with this.  If I write
> >
> > .global foo
> >
> > ...
> >        ldr r0, foo
> >
> > ...
> >
> > foo:
> >        ...
> >
> > but then at link/load time pre-empt foo with some other definition, that
> > will silently leave me with the wrong answer.
> >
> > It's clearly OK to do this if foo is protected or private, but not
> > otherwise.
> >
> > The existing error message is not very informative as to what the
> > problem is, but I'm not sure I agree with your solution...
> >
> > R.
> 
> That's a reasonable argument, but similarly to the ADR case, such code
> referencing global symbols is already allowed through for ARM _with no
> relocation emitted_  - the Thumb treatment is inconsistent and causes
> existing code which builds for ARM (but where symbol preemption may
> silently fail to work).  This raises non-trivial questions about which
> behaviour should be considered correct.
> 
> Unless there are some tricks I haven't thought of, it seems that ADR
> and PC-relative LDR and friends simply can't be generally preemptible,
> period -- because the relocation ranges these instructions support
> just aren't large enough to guarantee that a relocation on these
> instructions can ever be resolved except in a trivial subset of cases.
> 
> Solving this inconsistency requires a conclusion regarding whether the
> tools should trust the programmer to write correct code (i.e., fix up
> pc-relative LDR and ADR in the assembler and emit no relocation) or
> not (i.e., treat these instructions as an error when they reference
> global symbols).
> 
> I would regard the latter option as incorrect, since it's quite
> legitimate to use these instructions in this way in static
> environments, and the assembler doesn't have knowledge of whether this
> is what's intended.  There is also a possible middle way of allowing
> the instructions but always emitting a relocation, which allows a tool
> further down the line to check whether the preemption is needed and
> throw an error if so.  Since the Linux kernel doesn't do symbol
> preemption it can safely ignore these relocations with a tiny amount
> of extra code in the module loader.
> 
> In general, we can't expect to prevent absolutely the programmer from
> doing something that generates the wrong answer, such as writing
> non-PIC code and the linking it into a PIC environment; though any
> diagnostics which help avoid this happening by accident are still
> useful.
> 
> 
> To give the flipside to this, there is a case when the assembler knows
> that preemption absolutely must be supported, and that is when a
> symbol is declared weak.  So:
> 
> .type g, %function
> g:	ldr	r0, d
> 
> 	.weak d
> d:	.long 0
> 
> $ arm-linux-gnueabi-as --version
> GNU assembler (GNU Binutils for Ubuntu) 2.20.51.20100908
> [...]
> $ arm-linux-gnueabi-as -o tst.o tst.s && arm-linux-gnueabi-objdump -drt tst.o
> tst.s: Assembler messages:
> tst.s:2: Error: internal_relocation (type: OFFSET_IMM) not fixed up
> $ arm-linux-gnueabi-as -mthumb -o tst.o tst.s &&
> arm-linux-gnueabi-objdump -drt tst.o
> tst.s: Assembler messages:
> tst.s:2: Error: invalid offset, value too big (0xFFFFFFFFFFFFFFFC)
> 
> i.e., cryptic error messages aside, the assembler fails sensibly for
> ARM and Thumb alike.  This is appropriate, because ".weak" declares
> explicitly the need for preemptibility, and the assembler knows that
> can't be guaranteed with these instruction forms.  ".globl" does not,
> because where the symbol is not weak it's impossible for the assembler
> to know what the programmer intends, and so throwing an error for such
> cases seems too zealous from my point of view.
> 
> For comparison, changing ".weak" to ".globl" in the above example gives:
> $ arm-linux-gnueabi-as -o tst.o tst.s && arm-linux-gnueabi-objdump -drt tst.o
> [...]
> 00000004 g       .text	00000000 d
> [...]
> 00000000 <f>:
>    0:	e51f0004 	ldr	r0, [pc, #-4]	; 4 <d>
> 00000004 <d>:
>    4:	00000000 	.word	0x00000000
> 
> $ arm-linux-gnueabi-as -mthumb -o tst.o tst.s &&
> arm-linux-gnueabi-objdump -drt tst.o
> tst.s: Assembler messages:
> tst.s:2: Error: invalid offset, value too big (0xFFFFFFFFFFFFFFFC)
> 
> Notice that the ARM code refernce to d is not preemptible.
> 

It's easy for the user to express their intention, simply use
a .visibility (protected/hidden) directive (at least in ELF, and that's
what I really care about...).

Then the linker will (can be safely made to) permit the early resolution
of the symbol do the right thing, and will also do the right thing if
the user then accidentally tries to override the symbol later on.

The tools *can* correctly support the behaviours being asked for.  The
implementation is currently wrong.  The fact that there is broken code
out there that relies on the currently broken implementation is not
really an excuse for keeping the status quo.

R.



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]