Thumb relocation error

Dave Martin dave.martin at linaro.org
Wed May 25 13:51:23 UTC 2011


On Wed, May 25, 2011 at 10:17:23AM +0100, Tixy wrote:
> On Tue, 2011-05-24 at 17:54 +0100, Dave Martin wrote:
> > On Tue, May 24, 2011 at 04:30:23PM +0100, Tixy wrote:
> [...]
> > > The 'interesting' thing is branching from inline asm in a static
> > > function into inline asm in another non-static function. This test case
> > > reproduces it..
> > > 
> > > static void foo(void)
> > > {
> > > 	__asm__ __volatile__ (
> > > 		"b bar2"
> > > 	);
> > > }
> > > 
> > > void bar(void)
> > > {
> > > 	__asm__ __volatile__ (
> > > 		"bar2:"
> > > 	);
> > > }
> > > 
> > > As you say, neither the module loader or the toolchain seem to be doing
> > > anything wrong. The error is that the programmer (me) didn't provide the
> > > information that the label bar2 refers to a function. Adding the line
> > > ".type bar2, %function\n" before "bar2:" does this.
> > 
> > According to the gcc info docs, the above is wrong usage:
> > 
> > "Speaking of labels, jumps from one `asm' to another are not supported.
> > The compiler's optimizers do not know about these jumps, and therefore
> > they cannot take account of them when deciding how to optimize.  *Note
> > Extended asm with goto::.
> 
> My jump is semantically the same as a function call, because execution
> eventually returns back to just after the branch instruction.

Well yeees, you will get away with it.  The compiler really isn't designed
to cope with this sort of thing, though.

> 
> > 
> > I'm still not sure why you're getting a relocation (and hence a module
> > loading error).  One possibility is that the location of "b bar2" is
> > in a different section from the label bar2; for example, foo() is called
> > from an __init function, but bar() is part of the main module.
> 
> I think this is the situation, foo() is called from a module_init
> function, bar() is non-static so it doesn't get optimised out leaving
> label bar2 undefeined.

OK, that sounds like the explanation for the specific issue seen anyway.
In which case adding .type is correct (note that adding this is always
harmless anyway).

> 
> > Alternatively, gas might not be fixing the branch up at assembly time
> > due to some range issue.
> > 
> > So, the .type directive is strictly speaking correct, but normally it's
> > not needed when branching within a single file, unless the above
> > conditions apply.
> > 
> > 
> > Either way, jumping from one function to another is doubtless a bad 
> > idea... is there a cleaner way to achieve what you're trying to do?
> > 
> > More context might be helpful if you want suggestions.
> 
> The code in question is my module for testing kprobes. I have macros
> create test cases for probing different CPU instructions, each test case
> generates inline assembler.
> 
> void foo(void)
> {
> 	TEST("instruction_to_test1")
> 	TEST("instruction_to_test2")
> 	...
> }
> 
> Each TEST expands to something like
> 
> 	__asm__ __volatile__ (
> 	"bl	__test_case_start	\n\t"
> 	".word some, inline, data	\n\t"

.word doesn't implicitly align to a word boundary in Thumb, so you
may need .align before it.

.word in inline asm may cause branch fixup errors in the code generated
by the compiler, since the compiler has to guesstimate the size of output
code generate by the asm block.  Data directives, assembler macro expansion,
.align and ISA changes can all throw this estimate off.

In practice one tends to get away with this however: gcc assumes every 
instruction might expand to 32 bits even for Thumb-2.

For .word, it's therefore better not to declare more than one item per
statement.  (For .quad, .double etc., you just lose ... eventually)

> 	".code "TEST_ISA"		\n\t"

>From some conversations with tools guys, I remember that .arm/.thumb are
preferred to ".code".  You could generate this easily of TEST_ISA and
NORMAL_ISA are defined to "arm" and "thumb" instead of "32" and "16".

It's a minor thing though ... in reality I expect .code will continue
to be understood by the assembler forever in any case.

> 	"0:				\n\t"
> 	"instruction_to_test		\n\t"
> 	"b __test_case_end_"TEST_ISA"	\n\t"
> 	".align				\n\t"

(Actually, you don't need .align here, but it's harmless.  Unlike data,
every instruction emitted by the assembler is always aligned up to the
appropriate boundary depending on the ISA.)

> 	".code "NORMAL_ISA"		\n\t"
> 	"99:				\n\t"
> 	);
> 
> The __test_case_start and __test_case_end labels are test framework code
> written as inline assembler in another C function, i.e. bar() in my
> original example.
> 
> The TEST_ISA macro expands to '32' or '16' depending on whether I'm
> testing ARM or Thumb instructions, and NORMAL_ISA is 32 for ARM kernels
> and 16 for Thumb2 kernels.
> 
> The __test_case_end function iterates the test case several times by
> jumping back to label 0: and finishes by jumping back to label 99:

I see no C code except for void foo(void), __asm__ __volatile__, some
brackets and a lot of quote marks and backslashes, though I appreciate
we don't have the whole file here.

Is there any reason why this shouldn't be coded in out-of-line assembler
instead?  Then, most of the "how do I smuggle this past the compiler"
issues would just go away.

Cheers
---Dave




More information about the linaro-kernel mailing list