About "switch" coding with addresses jump table

Comments

13 comments

  • Avatar
    Michael Johnson

    Could you attach a code sample? What happens if you use the clang compiler/assembler rather than gcc (you can use Tools | Options to specify the compiler/assembler to use).

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    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.

    0
    Comment actions Permalink
  • Avatar
    Michael Johnson

    I don't see any attachments.

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    I see now I can attach only images; So I cannot send .scr and .asm files; I don't know what to do, now.

    Sorry for the mistake

    Giuliano

    0
    Comment actions Permalink
  • Avatar
    Michael Johnson

    Could you paste in the code of the switch statement

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli


     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

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    Please note: I check the suspect addresses in the .elf file and they are even.

    I loaded it on STM32f042 processor and I observe the R3 value before the "mov pc, R3" instruction and it is EVEN. Executing it the processor runs in hardfault handler.

    Giuliano

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    Errata-Corrige:

    At the  .60 label I made an error the comment:

    L60:
        .word    .L6                   @this is the value loaded in R2 in "ldr r2, .L60"
     at the 2nd instruction after .LCB68 label

    .................

    Sorry for the mistake.

    Giuliano

    0
    Comment actions Permalink
  • Avatar
    Michael Johnson

    I just tried the ST DFU_Standalone application in the STM32 Cube F0/STM32F072B-DIscovery. It contains this code which builds and runs okay. Which version of CrossWorks are you using?

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    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:

    1. I'm using an ARM Crossstudio, suited for every arm core, Cortex-M particularly.
    2. I've create a project for STM320F42 (Cortex-m0) with a project based on STM32 USB library.
    3. 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

    0
    Comment actions Permalink
  • Avatar
    Michael Johnson

    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.

    0
    Comment actions Permalink
  • Avatar
    Gcorticelli

    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

    0
    Comment actions Permalink
  • Avatar
    Michael Johnson

    I believe you, could there be an issue with reading from the flash?

    DD10419C is the ARMV6M architecture manual.

    Use "File | Import IAR/Keil Project" and point it at the IAR project file

    0
    Comment actions Permalink

Please sign in to leave a comment.