ARM: kprobes: Fix build error in test code
PATCH 1/1 ARM: kprobes: Fix build error in test code
When compiling kprobes-test-thumb.c an error like below may occur:
/tmp/ccKcuJcG.s:19179: Error: offset out of range
This is caused by the compiler underestimating the size of the inline assembler instructions containing ".space 0x1000" and failing to spill the literal pool in time to prevent the generation of PC relative load instruction with invalid offsets.
The fix implemented by this patch is to replace a single large .space directive by a number of 4 byte .space's. This requires splitting the macros which generate test cases for branch instructions into two forms:
one with, and one without support for inserting extra code between branch and target.
--- arch/arm/kernel/kprobes-test.h | 100 ++++++++++++++++++++++++---------- arch/arm/kernel/kprobes-test-thumb.c | 16 +++--- 2 files changed, 78 insertions(+), 38 deletions(-)
arch/arm/kernel/kprobes-test.h +70 -30
@@ -149,23 +149,31 @@ struct test_arg_end {"1: " instruction" \n\t" \ " nop \n\t" -#define TEST_BRANCH_F (instruction, xtra_dist) \ +#define TEST_BRANCH_F (instruction) \ TEST_INSTRUCTION(instruction) \ - ".if "#xtra_dist" \n\t" \ " b 99f \n\t" \ - ".space "#xtra_dist" \n\t" \ - ".endif \n\t" \ + "2: nop \n\t" + +#define TEST_BRANCH_B (instruction) \ + " b 50f \n\t" \ + " b 99f \n\t" \ + "2: nop \n\t" \ + " b 99f \n\t" \ + TEST_INSTRUCTION(instruction) + +#define TEST_BRANCH_FX (instruction, codex) \ + TEST_INSTRUCTION(instruction) \ + " b 99f \n\t" \ + codex" \n\t" \ " b 99f \n\t" \ "2: nop \n\t" -#define TEST_BRANCH_B (instruction, xtra_dist) \ +#define TEST_BRANCH_BX (instruction, codex) \ " b 50f \n\t" \ " b 99f \n\t" \ "2: nop \n\t" \ " b 99f \n\t" \ - ".if "#xtra_dist" \n\t" \ - ".space "#xtra_dist" \n\t" \ - ".endif \n\t" \ + codex" \n\t" \ TEST_INSTRUCTION(instruction)#define TESTCASE_END \
@@ -301,47 +309,60 @@ struct test_arg_end { TESTCASE_START(code1 #reg1 code2) \ TEST_ARG_PTR(reg1, val1) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg1 code2, 0) \ + TEST_BRANCH_F(code1 #reg1 code2) \ TESTCASE_END -#define TEST_BF_X (code, xtra_dist) \ +#define TEST_BF (code) \ TESTCASE_START(code) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code, xtra_dist) \ + TEST_BRANCH_F(code) \ TESTCASE_END -#define TEST_BB_X (code, xtra_dist) \ +#define TEST_BB (code) \ TESTCASE_START(code) \ TEST_ARG_END("") \ - TEST_BRANCH_B(code, xtra_dist) \ + TEST_BRANCH_B(code) \ TESTCASE_END -#define TEST_BF_RX (code1, reg, val, code2, xtra_dist) \ - TESTCASE_START(code1 #reg code2) \ - TEST_ARG_REG(reg, val) \ - TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg code2, xtra_dist) \ +#define TEST_BF_R (code1, reg, val, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_F(code1 #reg code2) \ TESTCASE_END -#define TEST_BB_RX (code1, reg, val, code2, xtra_dist) \ - TESTCASE_START(code1 #reg code2) \ - TEST_ARG_REG(reg, val) \ - TEST_ARG_END("") \ - TEST_BRANCH_B(code1 #reg code2, xtra_dist) \ +#define TEST_BB_R (code1, reg, val, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_B(code1 #reg code2) \ TESTCASE_END -#define TEST_BF (code) TEST_BF_X(code, 0) -#define TEST_BB (code) TEST_BB_X(code, 0) - -#define TEST_BF_R (code1, reg, val, code2) TEST_BF_RX(code1, reg, val, code2, 0) -#define TEST_BB_R (code1, reg, val, code2) TEST_BB_RX(code1, reg, val, code2, 0) -#define TEST_BF_RR (code1, reg1, val1, code2, reg2, val2, code3) \ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \ TEST_ARG_REG(reg1, val1) \ TEST_ARG_REG(reg2, val2) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3, 0) \ + TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3) \ + TESTCASE_END + +#define TEST_BF_X (code, codex) \ + TESTCASE_START(code) \ + TEST_ARG_END("") \ + TEST_BRANCH_FX(code, codex) \ + TESTCASE_END + +#define TEST_BB_X (code, codex) \ + TESTCASE_START(code) \ + TEST_ARG_END("") \ + TEST_BRANCH_BX(code, codex) \ + TESTCASE_END + +#define TEST_BF_RX (code1, reg, val, code2, codex) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_FX(code1 #reg code2, codex) \ TESTCASE_END#define TEST_X (code, codex) \
@@ -372,6 +393,25 @@ struct test_arg_end {TESTCASE_END +/* +* Macros for defining space directives spread over multiple lines. +* These are required so the compiler guesses better the length of inline asm +* code and will spill the literal pool early enough to avoid generating PC +* relative loads with out of range offsets. + */ +#define TWICE (x) x x +#define SPACE_0x8 TWICE(".space 4\n\t") +#define SPACE_0x10 TWICE(SPACE_0x8) +#define SPACE_0x20 TWICE(SPACE_0x10) +#define SPACE_0x40 TWICE(SPACE_0x20) +#define SPACE_0x80 TWICE(SPACE_0x40) +#define SPACE_0x100 TWICE(SPACE_0x80) +#define SPACE_0x200 TWICE(SPACE_0x100) +#define SPACE_0x400 TWICE(SPACE_0x200) +#define SPACE_0x800 TWICE(SPACE_0x400) +#define SPACE_0x1000 TWICE(SPACE_0x800) + +/* Various values used in test cases... */ #define N (val) (val ^ 0xffffffff)#define VAL1 0x12345678
arch/arm/kernel/kprobes-test-thumb.c +8 -8
@@ -222,8 +222,8 @@ void kprobe_thumb16_test_cases(void)DONT_TEST_IN_ITBLOCK ( TEST_BF_R( "cbnz r",0,0, ", 2f") TEST_BF_R( "cbz r",2,-1,", 2f") - TEST_BF_RX( "cbnz r",4,1, ", 2f",0x20) -TEST_BF_RX ("cbz r" ,7 ,0 ,", 2f" ,0x40 ) + TEST_BF_RX( "cbnz r",4,1, ", 2f", SPACE_0x20) +TEST_BF_RX ("cbz r" ,7 ,0 ,", 2f" , SPACE_0x40) ) TEST_R("sxth r0, r",7, HH1,"")TEST_R ("sxth r7, r" ,0 ,HH2 ,"" )
@@ -246,7 +246,7 @@ DONT_TEST_IN_ITBLOCK( TESTCASE_START(code) \ TEST_ARG_PTR(13, offset) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code,0) \ + TEST_BRANCH_F(code) \ TESTCASE_END TEST("push {r0}")
@@ -319,8 +319,8 @@ CONDITION_INSTRUCTIONS(8, TEST_BF( "b 2f") TEST_BB( "b 2b") - TEST_BF_X("b 2f", 0x400) - TEST_BB_X("b 2b", 0x400) + TEST_BF_X("b 2f", SPACE_0x400) + TEST_BB_X("b 2b", SPACE_0x400)TEST_GROUP ("Testing instructions in IT blocks" )
@@ -746,7 +746,7 @@ CONDITION_INSTRUCTIONS(22, TEST_BB("bne.w 2b") TEST_BF("bgt.w 2f") TEST_BB("blt.w 2b") - TEST_BF_X("bpl.w 2f",0x1000) + TEST_BF_X("bpl.w 2f", SPACE_0x1000) )TEST_UNSUPPORTED ("msr cpsr, r0" )
@@ -786,11 +786,11 @@ CONDITION_INSTRUCTIONS(22, TEST_BF( "b.w 2f") TEST_BB( "b.w 2b") - TEST_BF_X("b.w 2f", 0x1000) + TEST_BF_X("b.w 2f", SPACE_0x1000) TEST_BF( "bl.w 2f") TEST_BB( "bl.w 2b") - TEST_BB_X("bl.w 2b", 0x1000) + TEST_BB_X("bl.w 2b", SPACE_0x1000)TEST_X ("blx __dummy_arm_subroutine" , ".arm \n\t"
Signature · 1 line
1.7.4.1
PATCH 1/1 ARM: kprobes: Fix build error in test code
Quoted 9 lines · Jon Medhurst (Tixy)
When compiling
kprobes-test-thumb.can error like below may occur:
/tmp/ccKcuJcG.s:19179: Error: offset out of rangeThis is caused by the compiler underestimating the size of the inline assembler instructions containing ".space
0x1000" and failing to spill the literal pool in time to prevent the generation of PC relative load instruction with invalid offsets.
Quoted 8 lines
The fix implemented by this patch is to replace a single large .space directive by a number of 4 byte .space's. This requires splitting the macros which generate test cases for branch instructions into two forms:
one with, and one without support for inserting extra code between branch and target.Signed-off-by Jon Medhurst <[email protected]>---
Nicolas, I noticed that you put this patch into the Linaro kernel tree, can I take that as an Acked-by? ;-)
Signature · 1 line
Tixy
Quoted 215 lines
arch/arm/kernel/kprobes-test.h | 100 ++++++++++++++++++++++++---------- arch/arm/kernel/kprobes-test-thumb.c | 16 +++--- 2 files changed, 78 insertions(+), 38 deletions(-)arch/arm/kernel/kprobes-test.h +70
-30@@ -149,23 +149,31 @@ struct test_arg_end {"1: " instruction" \n\t" \ " nop \n\t" -#define TEST_BRANCH_F (instruction, xtra_dist) \ +#define TEST_BRANCH_F (instruction) \ TEST_INSTRUCTION(instruction) \ - ".if "#xtra_dist" \n\t" \ " b 99f \n\t" \ - ".space "#xtra_dist" \n\t" \ - ".endif \n\t" \ + "2: nop \n\t" + +#define TEST_BRANCH_B (instruction) \ + " b 50f \n\t" \ + " b 99f \n\t" \ + "2: nop \n\t" \ + " b 99f \n\t" \ + TEST_INSTRUCTION(instruction) + +#define TEST_BRANCH_FX (instruction, codex) \ + TEST_INSTRUCTION(instruction) \ + " b 99f \n\t" \ + codex" \n\t" \ " b 99f \n\t" \ "2: nop \n\t" -#define TEST_BRANCH_B (instruction, xtra_dist) \ +#define TEST_BRANCH_BX (instruction, codex) \ " b 50f \n\t" \ " b 99f \n\t" \ "2: nop \n\t" \ " b 99f \n\t" \ - ".if "#xtra_dist" \n\t" \ - ".space "#xtra_dist" \n\t" \ - ".endif \n\t" \ + codex" \n\t" \ TEST_INSTRUCTION(instruction)#define TESTCASE_END \@@ -301,47 +309,60 @@ struct test_arg_end { TESTCASE_START(code1 #reg1 code2) \ TEST_ARG_PTR(reg1, val1) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg1 code2, 0) \ + TEST_BRANCH_F(code1 #reg1 code2) \ TESTCASE_END -#define TEST_BF_X (code, xtra_dist) \ +#define TEST_BF (code) \ TESTCASE_START(code) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code, xtra_dist) \ + TEST_BRANCH_F(code) \ TESTCASE_END -#define TEST_BB_X (code, xtra_dist) \ +#define TEST_BB (code) \ TESTCASE_START(code) \ TEST_ARG_END("") \ - TEST_BRANCH_B(code, xtra_dist) \ + TEST_BRANCH_B(code) \ TESTCASE_END -#define TEST_BF_RX (code1, reg, val, code2, xtra_dist) \ - TESTCASE_START(code1 #reg code2) \ - TEST_ARG_REG(reg, val) \ - TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg code2, xtra_dist) \ +#define TEST_BF_R (code1, reg, val, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_F(code1 #reg code2) \ TESTCASE_END -#define TEST_BB_RX (code1, reg, val, code2, xtra_dist) \ - TESTCASE_START(code1 #reg code2) \ - TEST_ARG_REG(reg, val) \ - TEST_ARG_END("") \ - TEST_BRANCH_B(code1 #reg code2, xtra_dist) \ +#define TEST_BB_R (code1, reg, val, code2) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_B(code1 #reg code2) \ TESTCASE_END -#define TEST_BF (code) TEST_BF_X(code, 0) -#define TEST_BB (code) TEST_BB_X(code, 0) - -#define TEST_BF_R (code1, reg, val, code2) TEST_BF_RX(code1, reg, val, code2, 0) -#define TEST_BB_R (code1, reg, val, code2) TEST_BB_RX(code1, reg, val, code2, 0) -#define TEST_BF_RR (code1, reg1, val1, code2, reg2, val2, code3) \ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \ TEST_ARG_REG(reg1, val1) \ TEST_ARG_REG(reg2, val2) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3, 0) \ + TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3) \ + TESTCASE_END + +#define TEST_BF_X (code, codex) \ + TESTCASE_START(code) \ + TEST_ARG_END("") \ + TEST_BRANCH_FX(code, codex) \ + TESTCASE_END + +#define TEST_BB_X (code, codex) \ + TESTCASE_START(code) \ + TEST_ARG_END("") \ + TEST_BRANCH_BX(code, codex) \ + TESTCASE_END + +#define TEST_BF_RX (code1, reg, val, code2, codex) \ + TESTCASE_START(code1 #reg code2) \ + TEST_ARG_REG(reg, val) \ + TEST_ARG_END("") \ + TEST_BRANCH_FX(code1 #reg code2, codex) \ TESTCASE_END#define TEST_X (code, codex) \@@ -372,6 +393,25 @@ struct test_arg_end {TESTCASE_END +/* +* Macros for defining space directives spread over multiple lines. +* These are required so the compiler guesses better the length of inline asm +* code and will spill the literal pool early enough to avoid generating PC +* relative loads with out of range offsets. + */ +#define TWICE (x) x x +#define SPACE_0x8 TWICE(".space 4\n\t") +#define SPACE_0x10 TWICE(SPACE_0x8) +#define SPACE_0x20 TWICE(SPACE_0x10) +#define SPACE_0x40 TWICE(SPACE_0x20) +#define SPACE_0x80 TWICE(SPACE_0x40) +#define SPACE_0x100 TWICE(SPACE_0x80) +#define SPACE_0x200 TWICE(SPACE_0x100) +#define SPACE_0x400 TWICE(SPACE_0x200) +#define SPACE_0x800 TWICE(SPACE_0x400) +#define SPACE_0x1000 TWICE(SPACE_0x800) + +/* Various values used in test cases... */ #define N (val) (val ^ 0xffffffff)#define VAL1 0x12345678arch/arm/kernel/kprobes-test-thumb.c +8
-8@@ -222,8 +222,8 @@ void kprobe_thumb16_test_cases(void)DONT_TEST_IN_ITBLOCK ( TEST_BF_R( "cbnz r",0,0, ", 2f") TEST_BF_R( "cbz r",2,-1,", 2f") - TEST_BF_RX( "cbnz r",4,1, ", 2f",0x20) -TEST_BF_RX ("cbz r" ,7 ,0 ,", 2f" ,0x40 ) + TEST_BF_RX( "cbnz r",4,1, ", 2f", SPACE_0x20) +TEST_BF_RX ("cbz r" ,7 ,0 ,", 2f" , SPACE_0x40) ) TEST_R("sxth r0, r",7, HH1,"")TEST_R ("sxth r7, r" ,0 ,HH2 ,"" )@@ -246,7 +246,7 @@ DONT_TEST_IN_ITBLOCK( TESTCASE_START(code) \ TEST_ARG_PTR(13, offset) \ TEST_ARG_END("") \ - TEST_BRANCH_F(code,0) \ + TEST_BRANCH_F(code) \ TESTCASE_END TEST("push {r0}")@@ -319,8 +319,8 @@ CONDITION_INSTRUCTIONS(8, TEST_BF( "b 2f") TEST_BB( "b 2b") - TEST_BF_X("b 2f", 0x400) - TEST_BB_X("b 2b", 0x400) + TEST_BF_X("b 2f", SPACE_0x400) + TEST_BB_X("b 2b", SPACE_0x400)TEST_GROUP ("Testing instructions in IT blocks" )@@ -746,7 +746,7 @@ CONDITION_INSTRUCTIONS(22, TEST_BB("bne.w 2b") TEST_BF("bgt.w 2f") TEST_BB("blt.w 2b") - TEST_BF_X("bpl.w 2f",0x1000) + TEST_BF_X("bpl.w 2f", SPACE_0x1000) )TEST_UNSUPPORTED ("msr cpsr, r0" )@@ -786,11 +786,11 @@ CONDITION_INSTRUCTIONS(22, TEST_BF( "b.w 2f") TEST_BB( "b.w 2b") - TEST_BF_X("b.w 2f", 0x1000) + TEST_BF_X("b.w 2f", SPACE_0x1000) TEST_BF( "bl.w 2f") TEST_BB( "bl.w 2b") - TEST_BB_X("bl.w 2b", 0x1000) + TEST_BB_X("bl.w 2b", SPACE_0x1000)TEST_X ("blx __dummy_arm_subroutine" , ".arm \n\t"
PATCH 1/1 ARM: kprobes: Fix build error in test code
Quoted 16 lines · Jon Medhurst (Tixy)
Quoted 15 lines · Jon Medhurst (Tixy)
When compiling
kprobes-test-thumb.can error like below may occur:
/tmp/ccKcuJcG.s:19179: Error: offset out of rangeThis is caused by the compiler underestimating the size of the inline assembler instructions containing ".space
0x1000" and failing to spill the literal pool in time to prevent the generation of PC relative load instruction with invalid offsets.The fix implemented by this patch is to replace a single large .space directive by a number of 4 byte .space's. This requires splitting the macros which generate test cases for branch instructions into two forms:
one with, and one without support for inserting extra code between branch and target.
Quoted 5 lines
Quoted 2 lines
Signed-off-by Jon Medhurst <[email protected]>---
Nicolas, I noticed that you put this patch into the Linaro kernel tree, can I take that as an Acked-by? ;-)
Sure.
Nicolas