C language functions and assembly functions call each other

Publisher:乐观向前Latest update time:2021-06-23 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

Introduction: In the main function of the C program, the user inputs any integers, and then calls a function written in ARM assembly in main (in which the sorting function of these integers is completed), and then outputs these sorted integers in the main function of the C program.


main.c


#include

int main()



{

int i=0;

int num=0;

int *array=NULL;

while(num <= 0) //Enter the number of elements in the array



{

printf("please enter the number of elements:n");

scanf("%d",&num);

if(num > 0)



{

break;

}

}

if(NULL == (array = (int *)malloc(num*sizeof(int))))



{

printf("malloc failed!n");

exit(-1);

}

printf("please enter the elements:n");

for(i = 0; iprintf("n%d:t", i);

scanf("%d", array+i);

}

sort(array, num); //Call the corresponding assembly function, pay attention to the analysis of the parameter transfer process

printf("The Result is: n");

for(i = 0; iprintf("%d:t%dn", i, *(array+i));

}

return 0;

}




Here is the corresponding Sort.s:


.section .text; declared as a code section

.globl sort; declare global variables

sort: ; A colon is required in Linux

mov r2, #0

mov r8, r0

mov r9, r0

loop1:

sub r1, r1, #1

cmp r2, r1

add r1, r1, #1

beq end

mov r6, r2

add r3, r2, #1

loop2:

cmp r3, r1

beq continue1

mov r3, r3, lsl #2

add r8, r8, r3

ldr r5, [r8]

mov r6, r6, lsl #2

add r9, r9, r6

ldr r4, [r9]

cmp r4, r5

bgt exchange

continue2:

sub r8, r8, r3

mov r3, r3, lsr #2

sub r9, r9, r6

mov r6, r6, lsr #2

add r3, r3, #1

b loop2

exchange:

str r4, [r8]

str r5, [r9]

b continue2

continue1:

add r2, r2, #1

b loop1



end:




Note: The two variables passed through APCS are stored in r0 and r1, representing the first address and number of elements of the array respectively.

Use Arm cross-compilation through




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


For ARM system, the mixed calls between functions written in different languages ​​follow ATPCS (ARM-Thumb Procedure Call Standard). ATPCS mainly defines the rules for passing parameters when calling functions and how to return from functions. For details about ATPCS, please refer to Section 2.1 of ADS1.2 Online Books - Developer Guide. This document will talk about how to pass parameters when calling C functions in assembly code and how to return correctly from C functions.

Different from the parameter passing rules of x86, ATPCS recommends that the number of formal parameters of a function should not exceed 4. If the number of formal parameters is less than or equal to 4, the formal parameters are passed through the four registers R0, R1, R2, and R3; if the number of formal parameters is greater than 4, the part greater than 4 must be passed through the stack.

Let's first discuss the case where the number of formal parameters is 4.


Example 1:

test_asm_args.asm

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

IMPORT test_c_args ; declare test_c_args function

AREA TEST_ASM, CODE, READONLY

EXPORT test_asm_args

test_asm_args

STR lr, [sp, #-4]! ;Save current lr

ldr r0,=0x10 ; parameter 1

ldr r1,=0x20 ; parameter 2

ldr r2,=0x30 ; parameter 3

ldr r3,=0x40 ; parameter 4

bl test_c_args ;Call C function

LDR pc, [sp], #4; load lr into pc (return to main function)

END

test_c_args.c

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

void test_c_args(int a,int b,int c,int d)

{

printk("test_c_args:n");

printk("%0x %0x %0x %0xn",a,b,c,d);

}

main.c

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

int main()

{

test_asm_args();

for(;;);

}


The program starts from the main function. Main calls test_asm_args, test_asm_args calls test_c_args, and finally returns to main from test_asm_args. The code uses assembly and C to define two functions, test_asm_args and test_c_args. Test_asm_args calls test_c_args. The parameter passing method is to write parameter values ​​to R0~R3 respectively, and then use bl statement to call test_c_args. The statement marked in red is worth noting. Before calling test_c_args, test_asm_args must push the current lr into the stack. After calling test_c_args, write the lr just saved in the stack back to pc, so that it can return to the main function.

What if test_c_args has 8 parameters? In this case, how should test_asm_args pass the parameters?

Example 2:

test_asm_args.asm

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

IMPORT test_c_args ; declare test_c_args function

AREA TEST_ASM, CODE, READONLY

EXPORT test_asm_args

test_asm_args

STR lr, [sp, #-4]! ;Save current lr

ldr r0,=0x1 ; parameter 1

ldr r1,=0x2 ; parameter 2

ldr r2,=0x3 ; parameter 3

ldr r3,=0x4 ; parameter 4

ldr r4,=0x8

str r4,[sp,#-4]! ; Parameter 8 is pushed onto the stack

ldr r4,=0x7

str r4,[sp,#-4]! ; Parameter 7 is pushed onto the stack

ldr r4,=0x6

str r4,[sp,#-4]! ; Parameter 6 is pushed onto the stack

ldr r4,=0x5

str r4,[sp,#-4]! ; Parameter 5 is pushed onto the stack

bl test_c_args_lots

ADD sp, sp, #4; Clear parameter 5 in the stack. After this statement is executed, sp points to parameter 6

ADD sp, sp, #4; Clear parameter 6 in the stack. After this statement is executed, sp points to parameter 7

ADD sp, sp, #4; Clear parameter 7 in the stack. After this statement is executed, sp points to parameter 8

ADD sp, sp, #4; Clear parameter 8 in the stack. After this statement is executed, sp points to lr

LDR pc, [sp], #4; load lr into pc (return to main function)

END

test_c_args.c

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

void test_c_args(int a,int b,int c,int d,int e,int f,int g,int h)

{

printk("test_c_args_lots:n");

printk("%0x %0x %0x %0x %0x %0x %0x %0xn",

a,b,c,d,e,f,g,h);

}

main.c

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

int main()

{

test_asm_args();

for(;;);

}


This part of the code is mostly the same as the code in Example 1. The only difference is the number of parameters of test_c_args and the parameter passing method of test_asm_args.

In test_asm_args, parameters 1 to 4 are still passed through R0~R3, while parameters 5 to 8 are passed by pushing them into the stack. However, it should be noted that the order in which these four parameters are pushed into the stack is parameter 8-> parameter 7-> parameter 6-> parameter 5.


Until test_c_args is called, the stack contents are as follows:

sp->+----------+

| Parameter 5 |

+----------+

| Parameter 6 |

+----------+

| Parameter 7 |

+----------+

| Parameter 8 |

+----------+

| lr |

+----------+

After test_c_args returns, sp is set to clear the previously pushed parameters, and finally lr is loaded into pc to return to the main function. Before executing the LDR pc, [sp], #4 instruction, the stack content is as follows:

+----------+

| Parameter 5 |

+----------+

| Parameter 6 |

+----------+

| Parameter 7 |

+----------+

| Parameter 8 |

sp->+----------+

| lr |

+----------+


Reference address:C language functions and assembly functions call each other

Previous article:Analysis and solutions of three interrupt return situations of ARM microcontroller
Next article:ARM processor exception handling steps

Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号