We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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
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,