This describes how to write a member function of a class in assembler. The class in question is:
class CExample : public CBase
{
...
TInt32 AsmAddTo(TInt32 aVal);
TInt32 iAccessCount;
TInt32 iValue;
}
The first four parameters are passed to r0->r3 after that they are put on the stack 64 bit parameters may be passed in two registers
Non-static member functions have a pointer to the object as an invisble first parameter (ie this) so if you wish to access data members you can use r0. The layout of the data members in this version of gcc 32bit values seem to be layed out in the order they are declared in the class, 16bit values may be padded out so that the next 32bit value lies on a word boundary. The other thing to watch out for is that if your class has any virtual functions (or a subclass like CBase does) there will be a 32bit vtable pointer at the start of the class. You can work out the offset of a data member by writing some code that takes a pointer to the data member and subtracts the value of this.
So to access members in the example member AsmAddTo:
@@ r0 = CExample *this
@@ r1 = TInt32 aVal
ldmia r0,{r2,r3,r4} @@ load from r0, increment after loading each register
@@ this could have been ldmib r0,{r3,r4} as we don't
@@ really care about the vtable pointer
@@ now r2=vtable pointer
@@ r3=iAccessCount
@@ r4=iValue
add r3,r3,#1 @@ update the member variables
add r4,r4,r1
stmib r0,{r3,r4} @@ store back to r0, increment before (so we skip vtable ptr)
mov r0,r4 @@ move iValue into r0, ie return it.
The c++ for this would be:
TInt32 CExample::AsmAddTo(TInt32 aVal)
{
iAcessCount++;
iValue+=aVal;
return iValue;
}
To complete the function you need to save and restore the registers we have used and return to the caller:
stmfd r13!,{r2,r3,r4} @@ store r2-r4 on a full declining stack.
@@ we would have to store the link register if we where
@@ going to call another function from this one.
.... code above
ldmfd r13!,{r2,r3,r4} @@ restore r2-r4 from a full declining stack
bx lr @@ return to caller
check example works
check arm links & docs
We also need to work out what label to give the assembler function. To do this we can write a c++ stub for the function, compile it and see what label gcc gives the function. If the stub is in the file example.cpp which is part of the project example_app you can use:
abld listing armi urel example_app example.cpp
This will generate a file example.lis which should contain the label for the function eg:
...
.align 0
.global AsmAddTo__8CExamplel
AsmAddTo__8CExamplel:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, current_function_anonymous_args = 0
bx lr
...
So the label we need is AsmAddTo__8CExamplel.
Full function
So the final code is:
.global AsmAddTo__8CExamplel
AsmAddTo__8CExamplel:
stmfd r13!,{r3,r4} @@ store r3,r4 on a full declining stack.
@@ we would have to store the link register if we where
@@ going to call another function from this one.
@@ r0 = CExample *this
@@ r1 = TInt32 aVal
ldmib r0,{r3,r4} @@ load from r0, increment before loading
@@ each register
@@ r3=iAccessCount
@@ r4=iValue
add r3,r3,#1 @@ update the member variables
add r4,r4,r1
stmib r0,{r3,r4} @@ store back to r0, increment before
@@ (so we skip vtable ptr)
mov r0,r4 @@ move iValue into r0, ie return it.
ldmfd r13!,{r3,r4} @@ restore r3,r4 from a full declining stack
bx lr @@ return to caller
For more information there you can try http://www.arm.com/ if you follow the documentation link and then the TRMs link there is an arm instruction set quick reference card near the bottom of the page. If you take the Technical specs link there is a document on the arm thumb procuedure call standard.