实战汇编语言与 C 语言之间相互调用 您所在的位置:网站首页 c语言调用opencb 实战汇编语言与 C 语言之间相互调用

实战汇编语言与 C 语言之间相互调用

2023-01-05 03:08| 来源: 网络整理| 查看: 265

1. 引言

众所周知,C 语言相比于汇编语言拥有更为强大的灵活性和抽象能力,但相较于汇编语言,C 语言又缺乏了直接寻址、读写内存的强大能力。 同时,C 语言由于具备更强大的抽象能力,往往会造成生成的机器指令过多,因此,对于嵌入式编程等领域的 C 语言程序设计来说,有一个非常常用的优化方式,就是将 C 语言编译后反汇编为汇编语言,然后通过阅读并精简汇编语言,来实现代码优化的目的。 那么,既然 C 语言、C++ 可以被编译器反汇编为汇编语言,我们是否可以直接通过汇编语言调用 C 语言或者让 C 语言去调用汇编语言呢?答案当然是可以的。 本文,我们就来详细介绍,如何在 linux 环境下实现 C 语言与汇编语言的相互调用。

2. linux 系统调用的实现 — int 80h 中断2.1. 原理

各个操作系统都有一系列原生实现的系统调用,这些服务运行在操作系统内核,供用户态进程调用,从而实现了用户态进程对更高权限的使用。 此前我们已经介绍过,由于系统调用运行在 ring0 特权级,ring3 特权级的用户态进程必须通过四种调用门之一进行调用:

调用门中断门陷阱门任务门

利用调用门实现特权级间跳转(上) — 原理篇

linux 系统调用就是通过陷阱门实现的,它的调用过程如下:

应用程序调用库函数(API)API 将系统调用号存入 EAX,然后通过中断(int 0x80)调用使系统进入内核态内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用)系统调用完成相应功能,将返回值存入 EAX,返回到中断处理函数中断处理函数返回到 API 中API 将 EAX 返回给应用程序

因此,我们按照上述步骤设置寄存器、触发 80h 号中断就可以实现在汇编语言中调用 linux 系统调用了,具体的参数和系统调用编号见附录。 不过需要注意的是,windows 的 WSL 并不支持。

2.2. 实践

下面我们就来通过汇编实现在屏幕上打印 hello world。 查表可以看到,sys_write 的号码为 4,ebx 参数 fd 为 1 则表示 stdout,ecx、edx 分别是字符串指针和字符串长度。

2.2.1. hello.asm[section .data] ; 数据段 strHello db "Hello World", 0AH strlen equ $ - strHello [section .code] ; 代码段 global _start ; 导出程序入口 _start: mov edx, strlen mov ecx, strHello mov ebx, 1 ; stdout mov eax, 4 ; sys_write int 80h mov ebx, 0 mov eax, 1 ; sys_exit int 80h2.2.2. Makefilemain: nasm -f elf hello.asm -o hello.o ld -s hello.o -o hello clean: rm -rf hello.o hello2.2.3. 执行结果

运行 ./hello 可以看到打印出了执行结果:

Hello World

3. 汇编与 C 语言的相互调用3.1. 汇编调用 C 语言程序

上面的程序中,我们使用了 global 关键字,他的目的是导出入口,也就是供链接器识别程序调用的入口。 外部语言也可以通过这个导出的入口调用,我们也可以导出更多的函数供外部调用。 如果汇编程序需要依赖外部的程序入口,可以使用 extern 关键字,他用来导入外部程序入口。 但这里存在两个问题,也就是 C 调用约定:

参数压栈顺序 — C 语言参数列表中,后面的参数先压栈谁来清理堆栈 — 调用者清理3.2. C 语言调用汇编程序

在 C 语言中调用已经被汇编 global 关键字导出的代码也很简单,和调用其他动态链接库中的函数是一样的,只要显式声明即可直接调用。

3.3. 实践

下面我们就以汇编语言作为入口,调用 C 语言的快速排序程序。 当 C 语言中的快速排序完成时,调用汇编程序,实现结果的打印。

3.3.1. main.asmextern quick_sort ; void quick_sort(char *str, int len); [section .data] randstr db "cmyqpdexnlbzfsgtouhirvakjw" strlen equ $ - randstr [section .code] global _start ; 导出 _start 标记,供链接器识别程序入口 global print_text ; 导出打印程序供 C 语言调用 _start: push dword strlen ; len push dword randstr ; str call quick_sort ; 调用快速排序 add esp, 8 ; 清理堆栈 mov ebx, 0 mov eax, 1 ; sys_exit int 80h ; void print_text(char *str, int len) print_text: mov edx, [esp + 8] ; len mov ecx, [esp + 4] ; str mov ebx, 1 mov eax, 4 ; sys_write int 80h ret3.3.2. main.cvoid print_text(char *str, int len); void quick_sort(char *str, int len); void quick_sort_body(char *str, int start, int end); void exchange_char(char *str, int i, int j); void quick_sort(char *str, int len) { if (str == 0 || len


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有