如何实现汇编语言与 C 语言之间的相互调用

2020-07-05 20:24:49   最后更新: 2020-07-05 20:24:49   访问数量:102




众所周知,C 语言相比于汇编语言拥有更为强大的灵活性和抽象能力,但相较于汇编语言,C 语言又缺乏了直接寻址、读写内存的强大能力

同时,C 语言由于具备更强大的抽象能力,往往会造成生成的机器指令过多,因此,对于嵌入式编程等领域的 C 语言程序设计来说,有一个非常常用的优化方式,就是将 C 语言编译后反汇编为汇编语言,然后通过阅读并精简汇编语言,来实现代码优化的目的

那么,既然 C 语言、C++ 可以被编译器反汇编为汇编语言,我们是否可以直接通过汇编语言调用 C 语言或者让 C 语言去调用汇编语言呢?答案当然是可以的

本文,我们就来详细介绍,如何在 linux 环境下实现 C 语言与汇编语言的相互调用

 

 

原理

各个操作系统都有一系列原生实现的系统调用,这些服务运行在操作系统内核,供用户态进程调用,从而实现了用户态进程对更高权限的使用

此前我们已经介绍过,由于系统调用运行在 ring0 特权级,ring3 特权级的用户态进程必须通过四种调用门之一进行调用:

  1. 调用门
  2. 中断门
  3. 陷阱门
  4. 任务门

 

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

 

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

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

 

因此,我们按照上述步骤设置寄存器、触发 80h 号中断就可以实现在汇编语言中调用 linux 系统调用了,具体的参数和系统调用编号见附录

不过需要注意的是,windows 的 WSL 并不支持

 

实践

下面我们就来通过汇编实现在屏幕上打印 hello world

查表可以看到,sys_write 的号码为 4,ebx 参数 fd 为 1 则表示 stdout,ecx、edx 分别是字符串指针和字符串长度

 

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 80h

 

 

Makefile

main: nasm -f elf hello.asm -o hello.o ld -s hello.o -o hello clean: rm -rf hello.o hello

 

 

执行结果

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

Hello World

 

汇编调用 C 语言程序

上面的程序中,我们使用了 global 关键字,他的目的是导出入口,也就是供链接器识别程序调用的入口

外部语言也可以通过这个导出的入口调用,我们也可以导出更多的函数供外部调用

如果汇编程序需要依赖外部的程序入口,可以使用 extern 关键字,他用来导入外部程序入口

但这里存在两个问题,也就是 C 调用约定:

  1. 参数压栈顺序 -- C 语言参数列表中,后面的参数先压栈
  2. 谁来清理堆栈 -- 调用者清理

 

C 语言调用汇编程序

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

 

实践

下面我们就以汇编语言作为入口,调用 C 语言的快速排序程序

当 C 语言中的快速排序完成时,调用汇编程序,实现结果的打印

 

main.asm

extern 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 ret

 

 

main.c

void 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 <= 0) { print_text("params error\n", 13); return; } quick_sort_body(str, 0, len); print_text(str, len); print_text("\n", 1); return; } void quick_sort_body(char *str, int start, int end) { if (end <= start) { return; } int i = start + 1, j = start + 1; char temp; while (j < end) { if (str[j] < str[start]) { exchange_char(str, i, j); i++; } j++; } exchange_char(str, start, i-1); quick_sort_body(str, start, i-1); quick_sort_body(str, i, end); return; } void exchange_char(char *str, int i, int j) { char temp = str[i]; str[i] = str[j]; str[j] = temp; return; }

 

 

Makefile

main: nasm -f elf -o asm.o main.asm gcc -c -o main.o main.c ld -s -o main asm.o main.o clean: rm -rf asm.o main.o main

 

 

执行结果

执行 ./main 打印出了:

abcdefghijklmnopqrstuvwxyz

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 

 

https://zh.wikipedia.org/wiki/%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8

https://blog.csdn.net/xiaominthere/article/details/17287965

 

汇编调用 linux 系统调用参数
eaxNameSourceebxecxedxesxedi
1sys_exitkernel/exit.cint----
2sys_forkarch/i386/kernel/process.cstruct pt_regs----
3sys_readfs/read_write.cunsigned intchar *size_t--
4sys_writefs/read_write.cunsigned intconst char *size_t--
5sys_openfs/open.cconst char *intint--
6sys_closefs/open.cunsigned int----
7sys_waitpidkernel/exit.cpid_tunsigned int *int--
8sys_creatfs/open.cconst char *int---
9sys_linkfs/namei.cconst char *const char *---
10sys_unlinkfs/namei.cconst char *----
11sys_execvearch/i386/kernel/process.cstruct pt_regs----
12sys_chdirfs/open.cconst char *----
13sys_timekernel/time.cint *----
14sys_mknodfs/namei.cconst char *intdev_t--
15sys_chmodfs/open.cconst char *mode_t---
16sys_lchownfs/open.cconst char *uid_tgid_t--
18sys_statfs/stat.cchar *struct __old_kernel_stat *---
19sys_lseekfs/read_write.cunsigned intoff_tunsigned int--
20sys_getpidkernel/sched.c-----
21sys_mountfs/super.cchar *char *char *--
22sys_oldumountfs/super.cchar *----
23sys_setuidkernel/sys.cuid_t----
24sys_getuidkernel/sched.c-----
25sys_stimekernel/time.cint *----
26sys_ptracearch/i386/kernel/ptrace.clonglonglonglong-
27sys_alarmkernel/sched.cunsigned int----
28sys_fstatfs/stat.cunsigned intstruct __old_kernel_stat *---
29sys_pausearch/i386/kernel/sys_i386.c-----
30sys_utimefs/open.cchar *struct utimbuf *---
33sys_accessfs/open.cconst char *int---
34sys_nicekernel/sched.cint----
36sys_syncfs/buffer.c-----
37sys_killkernel/signal.cintint---
38sys_renamefs/namei.cconst char *const char *---
39sys_mkdirfs/namei.cconst char *int---
40sys_rmdirfs/namei.cconst char *----
41sys_dupfs/fcntl.cunsigned int----
42sys_pipearch/i386/kernel/sys_i386.cunsigned long *----
43sys_timeskernel/sys.cstruct tms *----
45sys_brkmm/mmap.cunsigned long----
46sys_setgidkernel/sys.cgid_t----
47sys_getgidkernel/sched.c-----
48sys_signalkernel/signal.cint__sighandler_t---
49sys_geteuidkernel/sched.c-----
50sys_getegidkernel/sched.c-----
51sys_acctkernel/acct.cconst char *----
52sys_umountfs/super.cchar *int---
54sys_ioctlfs/ioctl.cunsigned intunsigned intunsigned long--
55sys_fcntlfs/fcntl.cunsigned intunsigned intunsigned long--
57sys_setpgidkernel/sys.cpid_tpid_t---
59sys_oldunamearch/i386/kernel/sys_i386.cstruct oldold_utsname *----
60sys_umaskkernel/sys.cint----
61sys_chrootfs/open.cconst char *----
62sys_ustatfs/super.cdev_tstruct ustat *---
63sys_dup2fs/fcntl.cunsigned intunsigned int---
64sys_getppidkernel/sched.c-----
65sys_getpgrpkernel/sys.c-----
66sys_setsidkernel/sys.c-----
67sys_sigactionarch/i386/kernel/signal.cintconst struct old_sigaction *struct old_sigaction *--
68sys_sgetmaskkernel/signal.c-----
69sys_ssetmaskkernel/signal.cint----
70sys_setreuidkernel/sys.cuid_tuid_t---
71sys_setregidkernel/sys.cgid_tgid_t---
72sys_sigsuspendarch/i386/kernel/signal.cintintold_sigset_t--
73sys_sigpendingkernel/signal.cold_sigset_t *----
74sys_sethostnamekernel/sys.cchar *int---
75sys_setrlimitkernel/sys.cunsigned intstruct rlimit *---
76sys_getrlimitkernel/sys.cunsigned intstruct rlimit *---
77sys_getrusagekernel/sys.cintstruct rusage *---
78sys_gettimeofdaykernel/time.cstruct timeval *struct timezone *---
79sys_settimeofdaykernel/time.cstruct timeval *struct timezone *---
80sys_getgroupskernel/sys.cintgid_t *---
81sys_setgroupskernel/sys.cintgid_t *---
82old_selectarch/i386/kernel/sys_i386.cstruct sel_arg_struct *----
83sys_symlinkfs/namei.cconst char *const char *---
84sys_lstatfs/stat.cchar *struct __old_kernel_stat *---
85sys_readlinkfs/stat.cconst char *char *int--
86sys_uselibfs/exec.cconst char *----
87sys_swaponmm/swapfile.cconst char *int---
88sys_rebootkernel/sys.cintintintvoid *-
89old_readdirfs/readdir.cunsigned intvoid *unsigned int--
90old_mmaparch/i386/kernel/sys_i386.cstruct mmap_arg_struct *----
91sys_munmapmm/mmap.cunsigned longsize_t---
92sys_truncatefs/open.cconst char *unsigned long---
93sys_ftruncatefs/open.cunsigned intunsigned long---
94sys_fchmodfs/open.cunsigned intmode_t---
95sys_fchownfs/open.cunsigned intuid_tgid_t--
96sys_getprioritykernel/sys.cintint---
97sys_setprioritykernel/sys.cintintint--
99sys_statfsfs/open.cconst char *struct statfs *---
100sys_fstatfsfs/open.cunsigned intstruct statfs *---
101sys_iopermarch/i386/kernel/ioport.cunsigned longunsigned longint--
102sys_socketcallnet/socket.cintunsigned long *---
103sys_syslogkernel/printk.cintchar *int--
104sys_setitimerkernel/itimer.cintstruct itimerval *struct itimerval *--
105sys_getitimerkernel/itimer.cintstruct itimerval *---
106sys_newstatfs/stat.cchar *struct stat *---
107sys_newlstatfs/stat.cchar *struct stat *---
108sys_newfstatfs/stat.cunsigned intstruct stat *---
109sys_unamearch/i386/kernel/sys_i386.cstruct old_utsname *----
110sys_ioplarch/i386/kernel/ioport.cunsigned long----
111sys_vhangupfs/open.c-----
112sys_idlearch/i386/kernel/process.c-----
113sys_vm86oldarch/i386/kernel/vm86.cunsigned longstruct vm86plus_struct *---
114sys_wait4kernel/exit.cpid_tunsigned long *int optionsstruct rusage *-
115sys_swapoffmm/swapfile.cconst char *----
116sys_sysinfokernel/info.cstruct sysinfo *----
117sys_ipc (*Note)arch/i386/kernel/sys_i386.cuintintintintvoid *
118sys_fsyncfs/buffer.cunsigned int----
119sys_sigreturnarch/i386/kernel/signal.cunsigned long----
120sys_clonearch/i386/kernel/process.cstruct pt_regs----
121sys_setdomainnamekernel/sys.cchar *int---
122sys_newunamekernel/sys.cstruct new_utsname *----
123sys_modify_ldtarch/i386/kernel/ldt.cintvoid *unsigned long--
124sys_adjtimexkernel/time.cstruct timex *----
125sys_mprotectmm/mprotect.cunsigned longsize_tunsigned long--
126sys_sigprocmaskkernel/signal.cintold_sigset_t *old_sigset_t *--
127sys_create_modulekernel/module.cconst char *size_t---
128sys_init_modulekernel/module.cconst char *struct module *---
129sys_delete_modulekernel/module.cconst char *----
130sys_get_kernel_symskernel/module.cstruct kernel_sym *----
131sys_quotactlfs/dquot.cintconst char *intcaddr_t-
132sys_getpgidkernel/sys.cpid_t----
133sys_fchdirfs/open.cunsigned int----
134sys_bdflushfs/buffer.cintlong---
135sys_sysfsfs/super.cintunsigned longunsigned long--
136sys_personalitykernel/exec_domain.cunsigned long----
138sys_setfsuidkernel/sys.cuid_t----
139sys_setfsgidkernel/sys.cgid_t----
140sys_llseekfs/read_write.cunsigned intunsigned longunsigned longloff_t *unsigned int
141sys_getdentsfs/readdir.cunsigned intvoid *unsigned int--
142sys_selectfs/select.cintfd_set *fd_set *fd_set *struct timeval *
143sys_flockfs/locks.cunsigned intunsigned int---
144sys_msyncmm/filemap.cunsigned longsize_tint--
145sys_readvfs/read_write.cunsigned longconst struct iovec *unsigned long--
146sys_writevfs/read_write.cunsigned longconst struct iovec *unsigned long--
147sys_getsidkernel/sys.cpid_t----
148sys_fdatasyncfs/buffer.cunsigned int----
149sys_sysctlkernel/sysctl.cstruct __sysctl_args *----
150sys_mlockmm/mlock.cunsigned longsize_t---
151sys_munlockmm/mlock.cunsigned longsize_t---
152sys_mlockallmm/mlock.cint----
153sys_munlockallmm/mlock.c-----
154sys_sched_setparamkernel/sched.cpid_tstruct sched_param *---
155sys_sched_getparamkernel/sched.cpid_tstruct sched_param *---
156sys_sched_setschedulerkernel/sched.cpid_tintstruct sched_param *--
157sys_sched_getschedulerkernel/sched.cpid_t----
158sys_sched_yieldkernel/sched.c-----
159sys_sched_get_priority_maxkernel/sched.cint----
160sys_sched_get_priority_minkernel/sched.cint----
161sys_sched_rr_get_intervalkernel/sched.cpid_tstruct timespec *---
162sys_nanosleepkernel/sched.cstruct timespec *struct timespec *---
163sys_mremapmm/mremap.cunsigned longunsigned longunsigned longunsigned long-
164sys_setresuidkernel/sys.cuid_tuid_tuid_t--
165sys_getresuidkernel/sys.cuid_t *uid_t *uid_t *--
166sys_vm86arch/i386/kernel/vm86.cstruct vm86_struct *----
167sys_query_modulekernel/module.cconst char *intchar *size_tsize_t *
168sys_pollfs/select.cstruct pollfd *unsigned intlong--
169sys_nfsservctlfs/filesystems.cintvoid *void *--
170sys_setresgidkernel/sys.cgid_tgid_tgid_t--
171sys_getresgidkernel/sys.cgid_t *gid_t *gid_t *--
172sys_prctlkernel/sys.cintunsigned longunsigned longunsigned longunsigned long
173sys_rt_sigreturnarch/i386/kernel/signal.cunsigned long----
174sys_rt_sigactionkernel/signal.cintconst struct sigaction *struct sigaction *size_t-
175sys_rt_sigprocmaskkernel/signal.cintsigset_t *sigset_t *size_t-
176sys_rt_sigpendingkernel/signal.csigset_t *size_t---
177sys_rt_sigtimedwaitkernel/signal.cconst sigset_t *siginfo_t *const struct timespec *size_t-
178sys_rt_sigqueueinfokernel/signal.cintintsiginfo_t *--
179sys_rt_sigsuspendarch/i386/kernel/signal.csigset_t *size_t---
180sys_preadfs/read_write.cunsigned intchar *size_tloff_t-
181sys_pwritefs/read_write.cunsigned intconst char *size_tloff_t-
182sys_chownfs/open.cconst char *uid_tgid_t--
183sys_getcwdfs/dcache.cchar *unsigned long---
184sys_capgetkernel/capability.ccap_user_header_tcap_user_data_t---
185sys_capsetkernel/capability.ccap_user_header_tconst cap_user_data_t---
186sys_sigaltstackarch/i386/kernel/signal.cconst stack_t *stack_t *---
187sys_sendfilemm/filemap.cintintoff_t *size_t-
190sys_vforkarch/i386/kernel/process.cstruct pt_regs----

 

实现一个操作系统






技术帖      技术分享      系统调用      c      nasm      汇编      中断      syscall     


京ICP备15018585号