前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >汇编学习(9), 命令行参数,C与汇编

汇编学习(9), 命令行参数,C与汇编

作者头像
一只小虾米
发布2022-12-19 08:33:46
5690
发布2022-12-19 08:33:46
举报
文章被收录于专栏:Android点滴分享Android点滴分享

本篇介绍

本篇介绍下汇编如何支持命令行函数,以及C如何调用汇编。

命令行参数

看一个访问命令行参数的例子:

代码语言:javascript
复制
; cmdline.asm
section .data
    NL    db    10,0
    msg     db "The command and arguments: ",10,0
section .bss
section .text
    global main
main:
push rbp
mov rbp,rsp
    mov r12, rdi ;rdi contains number of arguments
    mov r13, rsi ;rsi contains the address to the array of arguments

printArguments:
    mov rdi, msg
    call printString
    mov rbx, 0 
printLoop:
    mov rdi, qword [r13+rbx*8] 
    call printString
    mov rdi, NL 
    call printString
    inc rbx
    cmp rbx, r12 
    jl printLoop
leave
ret


global printString
printString:
    push rbx
    push rax
    push r12
; Count characters 
    mov r12, rdi
    mov rdx, 0 
strLoop:
    cmp byte [r12], 0
    je strDone
    inc rdx                 ;length in rdx
    inc r12
    jmp strLoop
strDone:
    cmp rdx, 0              ; no string (0 length)
    je prtDone
    mov rsi,rdi
    mov rax, 1 
    mov rdi, 1
    syscall
prtDone:
    pop r12
    pop rax
    pop rbx
    ret
输出结果;
./cmdline 1 2 3
The command and arguments: 
./cmdline
1
2
3

命令行参数个数会保存到rdi中,rsi会记录包含参数地址的数组地址。 接下来也可以debug确认下:

代码语言:javascript
复制
gdb --args ./cmdline 1 2 hello
b main

(gdb) info registers rsi
rsi            0x7fffffffde88      140737488346760
(gdb) info registers rdi 
rdi            0x4                 4
(gdb) x /4xg 0x7fffffffde88
0x7fffffffde88: 0x00007fffffffe1f3  0x00007fffffffe252
0x7fffffffde98: 0x00007fffffffe254  0x00007fffffffe256

(gdb) x /s 0x00007fffffffe252
0x7fffffffe252: "1"
(gdb) x s 0x00007fffffffe254
No symbol "s" in current context.
(gdb) x /s 0x00007fffffffe254
0x7fffffffe254: "2"
(gdb) x /s 0x00007fffffffe256
0x7fffffffe256: "hello"

用 C 访问汇编

接下来写一个例子,用C访问汇编实现的函数,extern 声明的函数由汇编实现,C代码如下:

代码语言:javascript
复制
#include <stdio.h>
#include <string.h>

extern int rsurface(int, int);
extern int rcircum(int, int);
extern  double csurface( double);
extern  double ccircum( double);
extern void sreverse(char *, int );
extern void adouble(double [], int );
extern double asum(double [], int );

int main()
{

    char rstring[64];
    int side1, side2, r_area, r_circum;
    double radius,c_area, c_circum;
    double darray[] = {70.0, 83.2, 91.5, 72.1, 55.5};
    long int len;
    double sum;

// call an assembly function with int arguments
    printf("Compute area and circumference of a rectangle\n");
    printf("Enter the length of one side : \n");
    scanf("%d", &side1 );  
    printf("Enter the length of the other side : \n");
    scanf("%d", &side2 ); 
 
    r_area = rsurface(side1, side2);
    r_circum = rcircum(side1, side2);

    printf("The area of the rectangle = %d\n", r_area);
    printf("The circumference of the rectangle = %d\n\n",
 r_circum);

// call an assembly function with double (float) argument
    printf("Compute area and circumference of a circle\n");
    printf("Enter the radius : \n");
    scanf("%lf", &radius);  
 
    c_area = csurface(radius);
    c_circum = ccircum(radius);
    printf("The area of the circle = %lf\n", c_area);
        printf("The circumference of the circle = %lf\n\n", c_circum);

// call an assembly function with string argument
    printf("Reverse a string\n");
    printf("Enter the string : \n");
    scanf("%s", rstring);
    printf("The string is = %s\n", rstring);
    sreverse(rstring,strlen(rstring));
    printf("The reversed string is = %s\n\n", rstring);

// call an assembly function with array argument
    printf("Some array manipulations\n");
    len = sizeof (darray) / sizeof (double);

    printf("The array has %lu elements\n",len);
    printf("The elements of the array are: \n");
    for (int i=0;i<len;i++){
        printf("Element %d = %lf\n",i, darray[i]);
    }
    sum = asum(darray,len);
    printf("The sum of the elements of this array = %lf\n", sum);
    adouble(darray,len);
    printf("The elements of the doubled array are: \n");
    for (int i=0;i<len;i++){
        printf("Element %d = %lf\n",i, darray[i]);
    }
    sum = asum(darray,len);
    printf("The sum of the elements of this doubled array = %lf\n", sum);
    return 0;
}

对应的汇编如下:

代码语言:javascript
复制
; rect.asm
section .data                                       
section .bss                            
section .text

global rsurface

rsurface:
    section .text
        mov rax, rdi    
        imul    rsi
        ret                                 
global rcircum

rcircum:    
    section .text   
        mov rax, rdi
        add rax, rsi
        imul    rax, 2
        ret

; circle.asm
section .data                           
    pi  dq  3.141592654         

section .bss                            
section .text

global csurface
csurface:
    section .text   
        movsd   xmm1, qword [pi]
        mulsd   xmm0,xmm0       ;radius in xmm0
        mulsd   xmm0, xmm1
        ret
                                    
global ccircum
ccircum:
    section .text   
        movsd   xmm1, qword [pi]
        addsd   xmm0,xmm0       ;radius in xmm0
        mulsd   xmm0, xmm1
        ret

; sreverse.asm
section .data                           
section .bss                            
section .text

global sreverse
sreverse:

pushing:

        mov rcx, rsi
        mov rbx, rdi
        mov r12, 0
    pushLoop:
        mov rax, qword [rbx+r12]
                push rax
        inc r12
        loop pushLoop

popping:
        mov rcx, rsi
        mov rbx, rdi
        mov r12, 0
    popLoop:
        pop rax
        mov byte [rbx+r12], al 
        inc r12
        loop popLoop

exit:       mov rax, rdi
        ret

; asum.asm
section .data                           
section .bss                            
section .text

global asum
asum:
    section .text   
;calculate the sum
        mov rcx, rsi    ;array length
        mov rbx, rdi    ;address of array
        mov r12, 0
        movsd   xmm0, qword [rbx+r12*8]
        dec rcx  ; one loop less, first element already in xmm0
    sloop:  
        inc r12
        addsd   xmm0, qword [rbx+r12*8]
        loop sloop
ret     ; return sum in xmm0

; adouble.asm
section .data                           
section .bss                            
section .text

global adouble
adouble:
    section .text   
;double the elements
        mov rcx, rsi    ;array length
        mov rbx, rdi    ;address of array
        mov r12, 0
    aloop:
        movsd   xmm0, qword [rbx+r12*8] ;take an element from array
        addsd   xmm0,xmm0               ; double it
        movsd   qword [rbx+r12*8], xmm0 ;move it to array
        inc r12
        loop aloop
ret

输出如下:
Compute area and circumference of a rectangle
Enter the length of one side : 
10
Enter the length of the other side : 
20
The area of the rectangle = 200
The circumference of the rectangle = 60

Compute area and circumference of a circle
Enter the radius : 
5
The area of the circle = 78.539816
The circumference of the circle = 31.415927

Reverse a string
Enter the string : 
hello
The string is = hello
The reversed string is = olleh

Some array manipulations
The array has 5 elements
The elements of the array are: 
Element 0 = 70.000000
Element 1 = 83.200000
Element 2 = 91.500000
Element 3 = 72.100000
Element 4 = 55.500000
The sum of the elements of this array = 372.300000
The elements of the doubled array are: 
Element 0 = 140.000000
Element 1 = 166.400000
Element 2 = 183.000000
Element 3 = 144.200000
Element 4 = 111.000000
The sum of the elements of this doubled array = 744.600000

关键信息就是通过C调用汇编,还是按照调用约定就行,返回值用rax或xmm0传递。

内联汇编

首先除非必要,尽量不用内联汇编。 内联汇编有2种,Basic Inline 和 Extended Inline。

Basic Inline

首先看一个数字运算的例子:

代码语言:javascript
复制
#include <stdio.h>

int x=11,y=12,sum,prod;
int subtract(void);
void multiply(void);

int main(void)
{
    printf("The numbers are %d and %d\n",x,y);
    __asm__(
        ".intel_syntax noprefix;"   
        "mov rax,x;"
        "add rax,y;"
        "mov sum,rax"
        );
    printf("The sum is %d.\n",sum);
    printf("The difference is %d.\n",subtract());
    multiply();
    printf("The product is %d.\n",prod);    
    
}

int subtract(void)
{
    __asm__(
        ".intel_syntax noprefix;"   
        "mov rax,x;"
        "sub rax,y"         // return value in rax
        );
}

void multiply(void)
{
    __asm__(
        ".intel_syntax noprefix;"   
        "mov rax,x;"
        "imul rax,y;"
        "mov prod,rax"          //no return value, result in prod
        );
}

结果如下:
$ ./inline1 
The numbers are 11 and 12
The sum is 23.
The difference is -1.
The product is 132.

Basic 内联需要注意的点如下:

  • 第一行需要标明汇编类型,是ATT还是Intel,这样汇编器才会正确解析
  • 汇编用到的参数必须定义成全局变量
  • 如果使用的寄存器保存有关键数据,会被覆盖,这时候后果不确定,关于这一点通过 Extended Inline 可以解决。

Extended Inline

代码语言:javascript
复制
// inline2.c

#include <stdio.h>
    int a=12;   // global variables
    int b=13;
    int bsum;

int main(void)
{

printf("The global variables are %d and %d\n",a,b);
__asm__(
    ".intel_syntax noprefix\n"
    "mov rax,a \n"
    "add rax,b \n"
    "mov bsum,rax \n"
    :::"rax"
    );

     printf("The extended inline sum of global variables is %d.\n\n", bsum);

int x=14,y=16, esum, eproduct, edif;  // local variables

printf("The local variables are %d and %d\n",x,y);

__asm__( 
    ".intel_syntax noprefix;"
    "mov rax,rdx;"
    "add rax,rcx;"
    :"=a"(esum)
    :"d"(x), "c"(y)
    );
     printf("The extended inline sum is %d.\n", esum);

__asm__(
    ".intel_syntax noprefix;"
    "mov rbx,rdx;"
    "imul rbx,rcx;"
    "mov rax,rbx;"
    :"=a"(eproduct)
    :"d"(x), "c"(y)
    :"rbx"
    );
     printf("The extended inline product is %d.\n", eproduct);

__asm__(
    ".intel_syntax noprefix;"
    "mov rax,rdx;"
    "sub rax,rcx;"
    :"=a"(edif)
    :"d"(x), "c"(y)
    );
     printf("The extended inline asm difference is %d.\n", edif);

}

结果如下:
$ ./inline2 
The global variables are 12 and 13
The extended inline sum of global variables is 25.

The local variables are 14 and 16
The extended inline sum is 30.
The extended inline product is 224.
The extended inline asm difference is -2.

模式如下:

代码语言:javascript
复制
asm (
assembler code
: output operands
*//* optional
: input operands
*//* optional
: list of clobbered registers
*//* optional
);

可选部分需要按照寄存器约束,常用部分映射关系如下:

image.png

这儿明显的差异如下:

  • 通过寄存器显示传递参数
  • 需要声明可能会修改的寄存器,这样系统就会帮恢复原始值,避免异常
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-12-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本篇介绍
  • 命令行参数
  • 用 C 访问汇编
  • 内联汇编
    • Basic Inline
      • Extended Inline
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档