This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ARM, C and Assembly

Hi,
I want to write some subroutines with µVision3 in assembler and use this in my C-Funktions (Philips LPC2148). For example I have wrote(copied) this one:

//--------------------------------------------
//cpu_asm.asm 
//--------------------------------------------

NO_INT          EQU     0xC0

AREA    OSCPUSRSave, CODE
        PUBLIC  __OSCPUSRSave

__OSCPUSRSave   PROC    CODE32


    MRS     R0,CPSR
    ORR     R1,R0,#NO_INT
    MSR     CPSR_c,R1

    MRS     R1,CPSR
    AND     R1,R1,#NO_INT
    CMP     R1,#NO_INT

    BNE     __OSCPUSRSave
    BX      LR

ENDP

END

//--------------------------------------------


After that i declared in a C-File:

extern void __OSCPUSRSave(void);

Now i get every time the error Message: ***Warning L123: UNRESOLVED EXTERNAL SYMBOLS and ***ERROR L128: REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL: __OSCPUSave?T ADDRESS: 000003AAH I think the linker have to find the procedur because i wrote: PUBLIC __OSCPUSRSave , but he didn't.
I hope someone can help me, thanks.

  • What does the Manual say?

    Usually, the underscores are added by the compiler - so you have to write them in your assembler, but not in your 'C' source.
    You must read the Manual to check this...

  • The first thing to note is that your assembler code is ARM code and that you are using the Keil ARM compiler.

    __OSCPUSRSave   PROC    CODE32
    

    The second thing to note is that the linker is looking for a routine written for THUMB mode as evidenced by the ?T at the end of symbol in the linker error message.

    ***Warning L123: UNRESOLVED EXTERNAL SYMBOLS and ***ERROR L128: REFERENCE MADE TO UNRESOLVED EXTERNAL SYMBOL: __OSCPUSave?T ADDRESS: 000003AAH
    

    You can tell from this that the C file that references the function was compiled for THUMB mode. The ability to call code written in one mode from code written in another mode is called interworking. Veneers can be added to switch modes as needed. This is handled automatically by the compiler\linker for C code when interworking is enabled. You need to mimic the same operation when you write assembler code. Your function prototype was

    extern void __OSCPUSRSave(void);
    

    C code compiled for THUMB will look for a function called __OSCPUSRSave?T when it comes to the link stage. C code compiled for ARM will look for a function called __OSCPUSRSave?A when it comes to the link stage. You need to follow this convention to interface C to assembly. Note that this information is based on observing the code that is generated by the compiler. It's probably in the manual somewhere but I couldn't find it. The following sample code from the manual refers to this convention though.

    EXTERN DATA   (val)
    
    PUBLIC func2?A
    PUBLIC func2?T
    
    AREA ?PR?func2, CODE
    ; veneer code for ARM entry
    func2?A    PROC    CODE32       ; entry point for ARM mode call
               LDR     R12,[R15]    ; load Thumb entry
               BX      R12          ; switch to Thumb mode
               DD      func2?T
               ENDP
    
    ; entry point for Thumb mode call
    func2?T    PROC    CODE16
               PUSH    {LR}         ; save return address to stack
    ;---- Variable 'x1' passed in Register 'R0'
    ;---- Variable 'x2' passed in Register 'R1'
    ;   y = func1 (*x1, x2);
               LDR     R0,[R0,#0x0] ; load content of x1
    ;
    ;---- Variable 'v' passed in Register 'R0'
    ;---- Variable 'p' passed in Register 'R1'
               BL      func1?T      ; function call
    
    ;---- The function value of 'func1' is returned in Register 'R0'
    ;---- temporary Variable 'y' is saved in Register 'R0'
    ;   val += y;
               LDR      R1,=val      ; address of val
               LDR      R2,[R1,#0x0] ; load val
               ADD      R2,R0        ; add y to val
               STR      R2,[R1,#0x0] ; store val
    ;   return (y);
               POP      {R3}
               BX       R3
    
               ENDP
    
               END
    

  • Patrick Noonan you say it like it is. Your example had helped me. Thanks

  • Ok,
    Good one, THanks a lot,
    Bless you,

  • Franjo,

    I was wondering if this problem of yours is for some kind of RTOS for LPC2148? I have the same problems (I'm trying to port uC/OS-II using Keil). Did you solve your problems?

    Thank you

    BTW: where are you from? I'm from Slovenia

  • Hi,

    yeah i'm from croatia and i have solved the problem. When you want to port µC/OS you can visit the homepage http://www.micrium.com. There you can find a lot of portations. I have writen a OSEK conform OS based on µC/OS 2 knowlage.

    I have forgot how i solved my problem but here is the source code which i'm using now:

    AREA    OSCPU, CODE
    ...
    PUBLIC __OSCPUSRSave?A
    ...
    
    
    __OSCPUSRSave?A         PROC    CODE32
    
       STMFD   SP!, {R1}
       MRS     R0,CPSR
       ORR     R1,R0,#NO_INT
       MSR     CPSR_c,R1
    
       MRS     R1,CPSR
       AND     R1,R1,#NO_INT
       CMP     R1,#NO_INT
       BNE     __OSCPUSRSave?A
    
       LDMFD   SP!, {R1}
       BX      LR
    
    
    ENDP
    
    

    When you have some other questions you can write me a mail. I hope it help you

  • "you can visit the homepage http://www.micrium.com. "

    Note that the forum has included the full-stop in the hyperlink - so it won't work.

    Presumably, it should be: http://www.micrium.com (seemed to take a very long tie to load the first time)

    Seems to be the same as: www.ucos-ii.com/.../about.html

  • Note that the forum has included the full-stop in the hyperlink - so it won't work.

    It still works.

  • "It still works."

    So it does!

    http://www.micrium.com./

    Must just've been that it was taking so long that I gave up, and tried without the dot - and then got lucky!