1

Here is my code:

test.cpp

class Message
{
public:
    long long msgid;
    char* msgStr;
};

int foo(Message* msg)
{
    // TODO
    // print: msg->msgid, msg->msgStr
}

int main()
{
     char buf[20] = "Hello";
     Message msg = new Message;
     msg->msgid = 0x10;
     msg->msgStr = buf;

     foo(msg);

     call_from_arm((void*)&foo, (void*)msg);

     foo(msg);

     return 0;
}


test.S

call_from_arm:
@r0 = ptrFunc
@r1 = obj
STMFD   r13!, {r4-r11,r14}

MOV r8, r0              @r8 = ptrFunc
MOV r0, r1              @r0 = r1
BLX r8              @call ptrFunc

LDMFD   r13!, {r4-r11,pc}

When the application is running, I found that the parameter passed by call_from_arm to foo is correct(the address of msg), but the Message instance contains wrong values, as if contents on heap are offset.

the output of this application looks like:

msgid : 10, msgStr : Hello
msgid : (wrong value), msgStr : (wrong value, app may crash here)
msgid : 10, msgStr : Hello

The problem has been bothering me for several days. Please help me. Thanks

if I change class Message into

class Message
{
    char* msgStr;
}

I can print the correct value of string "Hello", so I think the problem may be bytes-align. long long is the key point. but I still don't know why.


I have solved this problem. AAPCS requires 8 bytes-align. 
My old version code store r4-r11 & lr into stack, whitch is not 8 bytes-aligned.
ZhangGuang
  • 53
  • 5
  • 3
    This is C++, not C. Also, if you don't show the assembly code, how do you expect to get help? – unwind Apr 08 '13 at 09:35
  • Since MsgStr is an sequence of chars, how does it detect the end of the sequence??? I think you should add a \0 at the end of the sequence. – Hugo Corrá Apr 08 '13 at 09:40
  • The assembly code is on the post. It's very simple, maybe too simple to do correct things :P – ZhangGuang Apr 08 '13 at 09:42
  • The key point is not the end of the sequence, I wonder why it contains the wrong value. – ZhangGuang Apr 08 '13 at 09:44
  • I think this requires investigating what code the compiler generates for your "call_from_arm". I have looked at similar code in Symbian's OS, and don't remember anything special about calling from ARM, so I suspect it's some type of confusion about arguments and order and such. – Mats Petersson Apr 08 '13 at 09:55
  • You should provide more information. What's on the heap? String is on the stack for sure. Are you sure that offset is not caused by structure member offset? – auselen Apr 08 '13 at 10:23
  • How the heck is `(wrong value)` being displayed? It is not in the code. Please show the actual code and output. – wallyk Apr 08 '13 at 13:03

1 Answers1

1

Please change your call_from_arm as follows,

 call_from_arm:
 @r0 = ptrFunc
 @r1 = obj

 MOV r2, r0              @r2 = ptrFunc
 MOV r0, r1              @r0 = r1
 BX  r2                  @call ptrFunc

I suspect you have messed up the stack somehow. The function int foo(Message* msg) should save all non-volatile registers. So there is no need to save r4-r11, if we don't use them. Also, the lr is already setup for a return, so you can use a tail function optimization and just jump to ptrFunc directly.

Also note, that you can improve on the C++ interface of call_from_arm by using function pointers.

 extern int call_from_arm(int (*ptrFunc)(Message* msg), Message* msg);
 /* ... */
 call_from_arm(foo, msg); /* no casting is better! */

As other have stated, more information would help to diagnose the problem. With the current information, we can only guess, as I have done.

artless noise
  • 21,212
  • 6
  • 68
  • 105
  • Specifically, your `foo()` may require a [stack frame](http://stackoverflow.com/questions/15752188/arm-link-register-and-frame-pointer) and be using `fp`; for instance `fp` portion of the EABI is not handled by the original `call_from_arm`. The suggested `call_from_arm` avoids touching `fp` and just juggles parameters and should be like a direct call. I imagine the only reason you would need `call_from_arm` is because of large code offsets. Just calling via a function pointer or using [`__attribute((long_call))`](http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Function-Attributes.html) in gcc. – artless noise Apr 08 '13 at 16:30
  • Thanks for your response. I chage my call_from_arm as you mentioned above. It actually works fine. It looks like that the problem is caused by "BLX". But, if I have to do something complecate in call_from_arm whitch may use r4-r11,what should i have to do? – ZhangGuang Apr 09 '13 at 02:32
  • There still one thing confused me. If i use r2 or r3 to store the pointer of func foo, the app works fine, but crash while using r4-r11 to store the pointer. – ZhangGuang Apr 09 '13 at 03:07
  • @ZhangGuang This has to do with a *definition/convention* that the *compilers* use called **EABI**. Registers `r0-r3` are free for a function to use. Also, parameters are passed in these. The calling function assumes they are destroyed. However, `r4-r11` are expected to be preserved. Otherwise, the assembler is not `C` compatible. Search for **ARM EABI** or look around StackOverflow. – artless noise Apr 09 '13 at 03:26