Hi,
I wrote a test function as;
// Task definitions OS_TID T_Test; U64 Test_stack[13312/8]; __task void init (void); __task void Test (void) ; // Function definition uint16_t TestFunc( uint8_t a0, uint8_t a1, uint8_t a2, uint16_t a3, uint8_t a4, uint8_t a7, uint16_t a9, uint16_t a10, uint8_t* a5, uint8_t* a6, uint8_t* a8, uint8_t* a11, uint8_t* a12, uint8_t* a13) { uint16_t x; //........ return 0; } __task void init (void) { /* Initialize Tasks */ T_Test = os_tsk_create_user (Test, 1, &Test_stack, sizeof(Test_stack)); os_tsk_delete_self(); } // Call Function __task void Test (void) { uint8_t x=9,*y; uint16_t z=0x1001; y=&x; x = TestFunc(x,x,x,z,x,x,z,z,y,y,y,y,y,y); os_tsk_delete_self(); }
The last two "y" are not equal to the address of the x. I need to know passing argument limitations and the reasons of this unexpected(according to me) condition.
Need help! (asap.)
Thanks.
My guess would be a stack alignment issue with all the uint8, uint16 and uint32 parameters being passed into this routine.
Check the memory space where the stack is located (ie: 'View Memory' window) to determine if the parameters in your call are there. Also, are the values you are seeing fragments of the correct address (ie: some hex values but not in proper order?).
If you want to pass that many parameters you usually just create a structure and pass in the structure's pointer to the function instead.
I need to know passing argument limitations and the reasons of this unexpected(according to me) condition.
The way in which all ARM compilers (should) pass arguments is defined in the "ARM Architecture Procedure Call Standard" (AAPCS).
infocenter.arm.com/.../IHI0042D_aapcs.pdf
That being said, I don't see any reason why your function call wouldn't work. Is there any reason why you aren't wrapping the arguments in a structure and simply passing a pointer to the structure? The reason I ask is because, as defined by the AAPCS, passing more than 4 arguments involves stack access (slow) and should be avoided if possible.
Thanks for your quick reply. If you want to pass that many parameters you usually just create a structure and pass in the structure's pointer to the function instead. I wrote "test" after got the error in my actual function which pass the pointers as you mentioned. i.e:
status = MyActualFunc( MyStruct1->a, MyStruct1->b, MyStruct1->c, MyStruct1->d, MyStruct1->e, MyStruct1->f, );
I saw the expected values in the stack, but not all values passed to the variables in the target function. Is it relaeted with the R0..R12 virtual register count? Because I detect the problem when I added the extra arguments. It's apparent that the problem is releated with stack, stack-pointer or something like that. I have to read the document (AAPCS) first of all.
I am waiting further suggestions. And I will share my observations.
Ally,
The reason I said it seems to be a stack alignment issue is because I ran into a similar issue when writing a routine to accept multiple paramters where this occurred.
The routine I used was something like this: void ChangeValue(UINT8 Bytes, UINT8 *p1, UINT32 *p2)
If I placed the parameters in another order such as: void ChangeValue(UINT8 *p1, UINT32 *p2, UINT8 Bytes)
The data was passed in without error. I could view the data in memory and see it was there, just not being recovered properly.
According the the document Drew linked in (good ref material BTW) there should not be any problems if the assembler follows that spec.
Set a breakpoint at the function call and step through the assembler when the data is placed into the stack, then watch the stack being populated. All data passed should be delinerated on a 4 byte boundary, according to the spec:
"B.2 If the argument is an integral Fundamental Data Type that is smaller than a word, then it is zero- or sign-extended to a full word and its size is set to 4 bytes."
Sorry, I meant view the *disassembly* window and step though the pushing and popping of the data from call and into function where it is recovered...
Also, your example of passing in your structure pointer....Why don't you just pass a pointer to MyStruct1 and operate on the elements within the function rather than passing the individual elements of the structure?
ie:
status = MyActualFunc(&MyStruct1);
then:
int MyActualFunc(struct *pMyStr) { }
Thank you Steve, I have to use a complex library written in C/C++.net. I am making some sort of reverse engineering. So I have limitted radius of action. Set a breakpoint at the function call and step through the assembler when the data is placed into the stack, then watch the stack being populated I will analize the code from assembly side as you mention.
waiting suggestions... Thanks.
Hi, In fact there was no problem. I wrote the test code attached below. When I debug the code, I saw that a12,a13,14 are not included the expected values on the local watch window. But when I assigned the argument to a temp value, the expected values called back from stack and saw the correct values on watch window assigned to the temp.
Thank you.
// Type Definition typedef struct { uint8_t a1[16]; uint8_t a2[16]; uint8_t a3[16]; uint8_t a4[16]; uint8_t a5; uint8_t a6[16]; uint8_t a7[16]; uint8_t a8[16]; uint8_t a9[16]; uint8_t a10; uint8_t a11[16]; uint8_t a12[16]; uint8_t a13[16]; uint8_t a14[16]; uint8_t a15; } TestType_t; // Test Functions // Function definitions void MyTestFunc_1( uint8_t *a1, uint8_t *a2, uint8_t *a3, uint8_t *a4, uint8_t a5, uint8_t *a6, uint8_t *a7, uint8_t *a8, uint8_t *a9, uint8_t a10, uint8_t *a11, uint8_t *a12, uint8_t *a13, uint8_t *a14, uint8_t a15) { uint8_t * x,y; x = a1; x = a2; x = a3; x = a4; y = a5; x = a6; x = a7; x = a8; x = a9; y = a10; x = a11; x = a12; x = a13; x = a14; y = a15; *x= y; } void MyTestFunc_2(TestType_t *a) { uint8_t * x,y; x = a->a1; x = a->a2; x = a->a3; x = a->a4; y = a->a5; x = a->a6; x = a->a7; x = a->a8; x = a->a9; y = a->a10; x = a->a11; x = a->a12; x = a->a13; x = a->a14; y = a->a15; *x= y; } // function calls __task void Test (void) { TestType_t *x; unsigned char i; //initial values for(i=0;i<16;i++) TestPTR->a1[i] = 0xa1; for(i=0;i<16;i++) TestPTR->a2[i] = 0xa2; for(i=0;i<16;i++) TestPTR->a3[i] = 0xa3; for(i=0;i<16;i++) TestPTR->a4[i] = 0xa4; TestPTR->a5 = 0xa5; for(i=0;i<16;i++) TestPTR->a6[i] = 0xa6; for(i=0;i<16;i++) TestPTR->a7[i] = 0xa7; for(i=0;i<16;i++) TestPTR->a8[i] = 0xa8; for(i=0;i<16;i++) TestPTR->a9[i] = 0xa9; TestPTR->a10 = 0xaa; for(i=0;i<16;i++) TestPTR->a11[i] = 0xab; for(i=0;i<16;i++) TestPTR->a12[i] = 0xac; for(i=0;i<16;i++) TestPTR->a13[i] = 0xad; for(i=0;i<16;i++) TestPTR->a14[i] = 0xae; TestPTR->a15 = 0xaf; // Test it! x=TestPTR; MyTestFunc_2(x); MyTestFunc_1(x->a1, x->a2, x->a3, x->a4, x->a5, x->a6, x->a7, x->a8, x->a9, x->a10, x->a11, x->a12, x->a13, x->a14, x->a15 ); os_tsk_delete_self(); }