二刷部分Chapter2 $\Longrightarrow$ 如何理解System call
问题:构造最小的”Hello world”程序
基本程序和静态编译
1
2
3
4
5
6
#include <stdio.h>
int main () {
printf ( "Hello world" );
return 0 ;
}
1
gcc -static hello.c -o hello && ./hello
编译出来很大(Ubuntu上约900KB)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gcc -c hello.c && objdump -d hello.o
hello.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 8d 05 00 00 00 00 lea 0x0( %rip) ,%rax # f <main+0xf>
f: 48 89 c7 mov %rax,%rdi
12: b8 00 00 00 00 mov $0 x0,%eax
17: e8 00 00 00 00 call 1c <main+0x1c>
1c: b8 00 00 00 00 mov $0 x0,%eax
21: 5d pop %rbp
22: c3 ret
就和普通的函数差不多,只有参数压栈,call和参数出栈的过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
gcc -c fun.c && objdump -d fun.o
fun.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 90 nop
9: 5d pop %rbp
a: c3 ret
可以看到不链接的话和普通的函数调用过程差不多
链接失败!
1
2
3
4
○ → ld hello.o
ld: 警告: 无法找到项目符号 _start; 缺省为 0000000000401000
ld: hello.o: in function ` main':
hello.c:(.text+0x18): undefined reference to `printf'
本来以为找的main
,但是它实际上在找_start
这个东西?
那我们就把main
改成_start
1
2
3
4
5
6
#include <stdio.h>
void _start () {
printf ( "Hello world" );
return 0 ;
}
ld仍然不予通过
-> 找不到printf?
1
2
3
4
5
#include <stdio.h>
void _start () {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
○ → gcc -c hello.c && objdump -d hello.o && ld hello.o
hello.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <_start>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 90 nop
9: 5d pop %rbp
a: c3 ret
对于没有while(1)的a.out,使用gdb狠狠的拷打调试
这个时候我们看到rsp的地址是合法的,里面的值是1,当执行ret后,rsp将栈顶的值1赋给了pc,gdb显示pc访问了非法位置
🤡呦吼,崩溃了!
CPU只会执行指令,该怎么停下来?(mov,add这些指令停不下来)
需要什么指令让它停下来? $\Longrightarrow$ System call
也就是管态
最小的Hello world
程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <sys/syscall.h>
. globl _start
_start :
movq $ SYS_write , % rax # write (
movq $ 1 , % rdi # fd = 1 ,
movq $ st , % rsi # buf = st ,
movq $ ( ed - st ), % rdx # count = ed - st
syscall # );
movq $ SYS_exit , % rax # exit (
movq $ 1 , % rdi # status = 1
syscall # );
st :
. ascii " \033 [01;31mHello, OS World \033 [0m \n "
ed :
编译后查看反汇编代码
1
○ → objdump -d a.out | less
查看反汇编代码
man syscall
查看syscall的文档
我们会发现,syscall会告诉我们在各种架构的计算机中该如何通过寄存器为syscall传入参数,man syscalls
会告诉我们Linux操作系统的接口
感谢
感谢jyy互助群里zweix 大佬提供的
jyyslide-md
使用过程中发现因为Windows很烂的编码问题始终会出现gbk解码错误的error,和zweix 大佬差不多沟通了大半个下午,由于懒得给vscode配环境直接改成手动print看数据🤣,感觉就是命令行传参编码的问题,最后终于找到了解决方法😆,只能说Windows这个编码设置也是没谁了。