On Wed, 2011-05-25 at 14:51 +0100, Dave Martin wrote:
On Wed, May 25, 2011 at 10:17:23AM +0100, Tixy wrote:
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.
In reality, there's more than just .word statements, there's data structures built up with more macros generating .byte, .short, .word and .ascii. Trust me, I have all alignment issues sorted :-)
.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".
I switched to .code so I could store TEST_ISA as a numerical flag in my data structures, I could easily change though.
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.)
I do need the align because otherwise the label 99: below won't be aligned, and that's the label test_case_end jumps back to.
".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.
test_case_{start,end} are mostly trampolines which call C code, but the functions containing the test cases themselves do just expand to asm statements. However, I make heavy use of macro expansion and string literal concatenation to paste together assembler instructions, I'm not sure I could do all of this in an assembler file. Anyway, I'd rather not redo weeks of work unless things are very broken.