About "switch" coding with addresses jump table
I'm developing a project on a Cortex-M0 processor, and I've a problem about a 'Switch" statement with procedure call in its "case"; The C compiler (Normally) codes this "Switch" with an indirect Jump Table; Please suppose the C file has name "Code_with_switch.c". If I see the corresponding "Code_with_Switch.asm" file the table contains some ".word Func_x_Address" statements for every "x" case; but in ARM-Cortex-M processors the Jump address MUST BE ODD, and in assembly this detail is solved specifying ".thumb_func" before every "Func_x_address". Unfortunately the compiler (with "natural ARM CORTEX" options) doesn't specify this Function nature, and at the end of the history the table contains EVEN addresses and the system crashes in HFault handler. To remove the problem I had to add the "-fno-jump-tables" in C compiler options. Inthiis way the "switch" iis solved in several "cmp Rx,#case" statements and the code doesn't crash any more, but the execution speed is slower and this coding is horrible. I serach in internet for about 8 hours the solution with a lot of "search" strings, but without success. In CrosssStudio Help I didn't find the solution. Please, can you help me?
-
Many Thanks.
I attached the "usb_ctlreq.c" and the complied "usb_ctlreq.asm".
In the second, at the label .L15, you can say a table of addresses (corresponding to 'switch' statement), and the coded addresses are obtained with ".word" keyword. Among (e.g) them there is ".L14" that is the below-staying routine start address, that begins with ''bl PA5_LH"; the table address is EVEN; in the "project".ELF file it is the same; the microprocessor programmed with that .elf file crashes in that point; with "-fno-jump-table" options the jumptable disappears and the code runs. The Assembler is gcc, not clang, I verified.
May thanks.
-
Well, I Try.I'm studying the STM32 USB library for some customizations, the source code is of ST.
Here is the C code; the PA5_LH3() is a routine that move PA5 pin to observe software passage:
//#################### Switch "C" Code #############
USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
{
USBD_StatusTypeDef ret = USBD_OK;
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR: //#6
PA5_LH3(); //USBD_StdDevRequest -> Get Descriptor, entry (LH3 #2)
USBD_GetDescriptor (pdev, req) ; //CRASH a questa istruzione, risolto; LH, poi OUT req->wvalue
PA5_LH3(); //USBD_StdDevRequest -> Get Descriptor, exit (LH3 #3)
break;
case USB_REQ_SET_ADDRESS: //#5
USBD_SetAddress(pdev, req);
break;
case USB_REQ_SET_CONFIGURATION: //#9
USBD_SetConfig (pdev , req);
break;
case USB_REQ_GET_CONFIGURATION: //#8
USBD_GetConfig (pdev , req);
break;
case USB_REQ_GET_STATUS: //#0
USBD_GetStatus (pdev , req);
break;
case USB_REQ_SET_FEATURE: //#3
USBD_SetFeature (pdev , req);
break;
case USB_REQ_CLEAR_FEATURE: //#1
USBD_ClrFeature (pdev , req);
break;
default:
USBD_CtlError(pdev , req);
break;
}
return ret;
}//==========================================
// NOW The corresponding compiled .asm code follows:
.section .text.USBD_StdDevReq,"ax",%progbits
.align 2
.global USBD_StdDevReq
.code 16
.thumb_func
.type USBD_StdDevReq, %function
USBD_StdDevReq:
.LFB34:
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 0, uses_anonymous_args = 0
push {r4, r5, r6, lr}
.LCFI1:
sub sp, sp, #8
.LCFI2:
movs r5, r0
movs r4, r1
ldrb r3, [r1, #1] @Switch variable in R3 (!) (0..15)
cmp r3, #9 @compare with last valid value
bls .LCB68 @if 9 or lower jump below
b .L4 @long jump @error, uniseful in this discussion
.LCB68:
lsls r3, r3, #2 @multiply by 4 for .L6 Table word access
ldr r2, .L60 @read table start from .L60 (R2=.L6)
ldr r3, [r2, r3] @read the word Number (!) starting by .L6
mov pc, r3 @execute jump. BUT HERE R3 MUST BE ODD; here the software crashes
.section .rodata.USBD_StdDevReq,"a",%progbits
.align 2
.L6: @WARNING! With ARM-Cortex these addresses MUST BE ODD! You can solve adding to these words "+1", OR declaring ".thumb_func" every tabled function (assembler automatically set addresses odd)
.word .L5 @item for R3(!)=0
.word .L7
.word .L4
.word .L8
.word .L4
.word .L9
.word .L10 @This is the Item selected by R3(!)=6
.word .L4
.word .L11
.word .L12.section .text.USBD_StdDevReq; HERE Below should appairs ".thumb_func"
.L10: @start of selected routine with R3(!)=6
.LBB18:
bl PA5_LH3 @as in C statement [see; "PA5_LH3();"]
.LBB19: @etcetera
.LBB20: @etcetera
ldrh r2, [r4, #2] @...........
ldr r3, .L60+ @......................................................
@----- some rows below there is the .L60 label with some pointers:
.........................................
.L60:
.word .L6 @this is the value loaded in R3 in (1)
.word .LANCHOR0 @unuseful in this discussion...
.word .L15 @rthe same........................
Finished; I hope the example is clear and You can help me.
Grateful for this
Giuliano
-
Hi, excuse me for late answer.
OK, thanks for your test. I use Crossstudio 3.7.1 recently updated.
Im not using STM32 Cube software, but another project suggested by STM Online-Help.
But...in every case:
- I'm using an ARM Crossstudio, suited for every arm core, Cortex-M particularly.
- I've create a project for STM320F42 (Cortex-m0) with a project based on STM32 USB library.
- I corretcly Compile every file and link them without errors.
Why the code is not well-suited for cortex-M0 core? Why an indirect jump (functions) address does not have correct (odd) addresses?
Which are differences between your compilation and my?
Thanks if you can explain to me.
The code I sent you was useful to understand? or not?
Thanks in advance.
Giuliano
-
I don't know what the problem is - the STM32Cube software I compiled generated a jump table containing even addresses that works on hardware.
According to DD10419C
mov PC, rm
does ALUWritePC(result)
which is defined as
ALUWritePC(bits(32) address) { BranchWritePC(address); }
and BranchWritePC is defined as
BranchWritePC(bits(32) address) { BranchTo(address<31:1>:’0’); }
So I suspect something else is causing the hardfault.
-
Many thanks, Michael, for your generose help.
Unfortunately, I surely (100% sure) check the r3 value (using three systems) at the 'mov pc, r3" instruction, and R3 value in even. Surely (100%) it is that instruction that cause HFault; the table written in flash (.rodata), relative to that "switch" statement (I see every "case" address), unfortunately contains even addresses; I don't know why. And changing Compiler option (no-jump-tables) solves the problem, and this is the fourth check about the problem.
About your important suggestion...what does "DD10419C" mean?
Excuse me, please, if the question is trivial, but I don't know the meaning.
I think I'll try with your proposed project from STM32cube and I'll see if something will change.
Grateful for your help.
Giuliano
Please sign in to leave a comment.
Comments
13 comments