第47部分- Linux x86 64位汇编 C调用汇编

第47部分- Linux x86 64位汇编 C调用汇编

这个部分我们直接以例子来展示。

示例

定义casm.c文件如下:

#include <string.h>

int main() {
	char* str = "Hello World\n";
	int len = strlen(str);
	printHelloWorld(str, len);
	return 0;
}

调用printHelloWorld函数,我们知道在X86处理中调用函数的前6个参数位于寄存器rdi, rsi, rdx, rcx, r8 and r9中,其他通过栈来实现。这样printHelloWorld函数可以通过rdi,rsi来获取前两个参数。

Nasm汇编器语法

再来看汇编文件,定义汇编文件printHelloWorld.s如下:

global printHelloWorld
section .text
printHelloWorld:
		;; 参数一
		mov r10, rdi
		;; 参数二
		mov r11, rsi
		;; 调用write系统调用
		mov rax, 1
		mov rdi, 1
		mov rsi, r10
		mov rdx, r11
		syscall
		ret

nasm -f elf64 -o printHelloWorld.o printHelloWorld.asm

gcc printHelloWorld.o casm.c -o casm

然后执行我们可以得到如下:

#./casm

Hello World

Gas汇编器语法

修改成gas的AT&T语法

printHelloWorld.s如下:

.global printHelloWorld
.section .text
printHelloWorld:
		mov %rdi, %r10
		mov %rsi, %r11
		mov $1,%rax
		mov $1,%rdi
		mov %r10,%rsi
		mov %r11,%rdx
		syscall
		ret

as -o printHelloWorld.o printHelloWorld.s

gcc printHelloWorld.o casm.c -o casm

得到的结果是一样的。

 

示例二求平方

先定义个求平方的汇编函数在文件square.s中如下:

.type square, @function
.globl square
square:
  movq %rdi,%rax
  imul %rax, %rax
  ret

然后C语言去调用

#include <stdio.h>

int main()
{
        int i = 2;
        int j = square(i);
        printf("The square of %d is %d\n", i, j);

        j = square(10);
        printf("The square of 10 is %d\n", j);
        return 0;
}

编译

gcc -o inttest inttest.c square.s

我们看到第一次使用了C变量i,第二次使用了立即数10。返回值被赋值给C变量j。这里我们要知道的是函数传递的时候前面六个寄存器是:

rdi,rsi,rdx,rcx,r8,r9.

示例三返回字符串

字符串比较长,只能通过返回字符串指针的方式来进行了。

这里需要提醒的事C/C++程序中处理器字符串时候,字符串必须使用空字符结尾。

默认情况下,C程序假设函数返回值是整数值。需要通知编译器这个函数范湖字符串指针,通过创建函数调用的原型来完成这个任务。

原型在使用函数之间定义。

以获取CPUID字符串为例子。

定义cpuidfunc.s汇编文件如下:

.section .bss
   .comm output, 13
.section .text
.type cpuidfunc, @function
.globl cpuidfunc
cpuidfunc:
   movq $0, %rax
   cpuid
   movq $output, %rdi
   movq %rbx, (%rdi)
   movq %rdx, 4(%rdi)
   movq %rcx, 8(%rdi)
   movq $output, %rax
   ret

这里定义了一个缓冲区,将被主C程序访问。

定义C文件stringtest.c如下:

#include <stdio.h>

char *cpuidfunc(void);

int main()
{
        char *spValue;
        spValue = cpuidfunc();
        printf("The CPUID is: '%s'\n", spValue);
        return 0;
}

编译:

gcc -o stringtest stringtest.c cpuidfunc.s -no-pie

 

示例三返回浮点值

浮点返回值是特殊情况。

整数和字符串返回值都是使用EAX寄存器把值从汇编语言函数返回到发出调用的C程序。

C样式使用xmm0寄存器在函数之间交换浮点值。函数把返回值存放到FPU堆栈中,然后调用程序负责把返回值弹出堆栈并且把它赋值给变量。

定义汇编函数areafunc.s如下:

.section .text
.type areafunc, @function
.globl areafunc
areafunc:
   fldpi
   push %rdi
   fild (%rsp)
   fmul %st(0), %st(0)
   fmul %st(1), %st(0)
   fstps (%rsp)
   movq (%rsp),%xmm0
   popq %rdi
   ret

先加载π到fpu堆栈中。然后加载半径到st0,然后半径自己相乘,最后与π相乘。最后要把结果放到xmm0中才可以。

定义C文件floattest.c如下:

#include <stdio.h>

float areafunc(int);//声明函数

int main()
{
        int radius = 10;
        float result;
        result = areafunc(radius);
        printf("The result is %f\n", result);

        result = areafunc(2);
        printf("The result is %f\n", result);
        return 0;
}

编译:

gcc -o floattest floattest.c areafunc.s

输出结果如下:

# ./floattest

The result is 314.159271

The result is 12.566371

 

示例四混合数据类型输入值

以一个双精度浮点输入值和一个整数输入值的汇编语言函数为例子。

汇编文件testfunc.s如下:

.section .text
.type testfunc, @function
.globl testfunc
testfunc:
   pushq %rdi;//第一个整型参数位于rdi寄存器中
   filds (%rsp)
   movq %xmm0, %rsi;//浮点参数位于xmm0寄存器中
   pushq %rsi
   fldl (%rsp)
   fmul %st(1),%st(0)
   fstpl (%rsp)
   movq (%rsp),%xmm0
   popq %rsi
   popq %rdi

   ret

第一个参数是双精度浮点值,第二个参数是整数。

定义C语言文件prog.c如下:

#include <stdio.h>

double testfunc(double, int);

int main()
{
        double data1 = 3.14159;
        int data2 = 10;
        double result;

        result = testfunc(data1, data2);
        printf("The proper result is %f\n", result);
        return 0;
}

编译文件如下:

gcc -g -o prog prog.c testfunc.s

示例五超6个参数输入

这里共8个参数。计算表达式:((43.65/22+(76.34*3.1))/((12.43*6)-(140.2/94.21))

定义汇编文件fpmathfunc.s

.section .text
.type fpmathfunc, @function
.globl fpmathfunc
fpmathfunc:

   push %rdi;//第一个整数参数value2, 56(%rsp)
   push %rsi;//第二个整数参数value6, 48(%rsp)
   movq %xmm0, %rsi
   push %rsi;// 第一个浮点参数value1, 40(%rsp)
   movq %xmm1, %rsi 
   push %rsi;// 第二个浮点参数value3, 32(%rsp)
   movq %xmm2, %rsi 
   push %rsi;// 第三个浮点参数value4, 24(%rsp)
   movq %xmm3, %rsi 
   push %rsi ;// 第四个浮点参数value5, 16(%rsp)
   movq %xmm4, %rsi 
   push %rsi ;// 第五个浮点参数value7,8(%rsp)
   movq %xmm5, %rsi 
   push %rsi ;// 第六个浮点参数value8,(%rsp)
   flds 40(%rsp)
   fidiv 56(%rsp)
   flds 32(%rsp)
   flds 24(%rsp)
   fmul %st(1), %st(0)
   fadd %st(2), %st(0)
   flds 16(%rsp)
   fimul 48(%rsp)
   flds 8(%rsp)
   flds (%rsp)
   fdivrp
   fsubr %st(1), %st(0)
   fdivr %st(2), %st(0)
   fsts (%rsp)
   movq (%rsp),%xmm0
//恢复栈,压栈几次出栈几次,都可以丢给rdi寄存器,反正用不到了,或者直接操作rsp寄存器。
   addq $64,%rsp
   ret
# fpmathfunc.s - An example of reading multiple input values

定义C文件mathtest.c程序如下:

#include <stdio.h>

float fpmathfunc(float, int, float, float, float, int, float, float);

int main()
{
        float value1 = 43.65;//浮点参数
        int value2 = 22; //第一个整型参数
        float value3 = 76.34; //浮点参数
        float value4 = 3.1; //浮点参数
        float value5 = 12.43; //浮点参数
        int value6 = 6; //整型参数
        float value7 = 140.2; //浮点参数
        float value8 = 94.21; //浮点参数
        float result;
        result = fpmathfunc(value1, value2, value3, value4,
                            value5, value6, value7, value8);
        printf("The final result is %f\n", result);
        return 0;
}

编译gcc -o -g mathtest mathtest.c fpmathfunc.s

# ./mathtest

The final result is 3.264907

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值