Open supergem3000 opened 7 months ago
操作系统:设计与实现 (2023 春季学期) (jyywiki.cn) 构建最小的Hello World // minimal.c int main() { } 生成目标文件gcc -c minimal.c 查看二进制文件 objdump -d minimal.o minimal.o: 文件格式 elf64-x86-64
操作系统:设计与实现 (2023 春季学期) (jyywiki.cn)
// minimal.c int main() { }
生成目标文件gcc -c minimal.c 查看二进制文件 objdump -d minimal.o
gcc -c minimal.c
objdump -d minimal.o
minimal.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 : 0: 55 push %rbp 1: 48 89 e5 mov %rsp,%rbp 4: b8 00 00 00 00 mov $0x0,%eax 9: 5d pop %rbp a: c3 ret
手动进行链接 `ld minimal.o -e main`,得到最小的a.out,运行时发生了Segmentation Fault。
┌────────────────────────────────────────────────────────┐ │ 0x401000 push %rbp │ │ 0x401001 <main+1> mov %rsp,%rbp │ │ 0x401004 <main+4> mov $0x0,%eax │ │ 0x401009 <main+9> pop %rbp │ │ > 0x40100a <main+10> ret │ │ 0x40100b add %al,(%rax) │ │ 0x40100d add %al,(%rax) │ │ 0x40100f add %al,(%rax) │ └────────────────────────────────────────────────────────┘ native process 863 In: main L?? PC: 0x40100a (gdb) si 0x0000000000401001 in main () 0x0000000000401004 in main () 0x0000000000401009 in main () 0x000000000040100a in main () (gdb) p $rsp $1 = (void *) 0x7fffffffdd20 (gdb) x $rsp 0x7fffffffdd20: 0x00000001 (gdb)
使用gdb调试查看,执行到ret指令时,把0x00000001地址给到pc,非法地址。 那么如何将程序正确的停下来?这时需要一条特殊的指令:syscall。 执行syscall,操作系统接管程序 - 程序把控制权完全交给操作系统 - 操作系统可以改变程序状态甚至终止程序 因此写一个最小的Hello World如下:
.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:
# 理解高级语言程序 汉诺塔程序 ```c void hanoi(int n, char from, char to, char via) { if (n == 1) { printf("%c -> %c\n", from, to); } else { hanoi(n - 1, from, via, to); hanoi(1, from, to, via); hanoi(n - 1, via, to, from); } }
怎么写一个非递归的汉诺塔?
typedef struct { int pc, n; char from, to, via; } Frame; #define call(...) ({ *(++top) = (Frame) { .pc = 0, __VA_ARGS__ }; }) #define ret() ({ top--; }) #define goto(loc) ({ f->pc = (loc) - 1; }) void hanoi(int n, char from, char to, char via) { Frame stk[64], *top = stk - 1; call(n, from, to, via); for (Frame *f; (f = top) >= stk; f->pc++) { n = f->n; from = f->from; to = f->to; via = f->via; switch (f->pc) { case 0: if (n == 1) { printf("%c -> %c\n", from, to); goto(4); } break; case 1: call(n - 1, from, via, to); break; case 2: call( 1, from, to, via); break; case 3: call(n - 1, via, to, from); break; case 4: ret(); break; default: assert(0); } } }
编译器做的其实也是把high level代码翻译成指令的行为。
有两种状态机:
与日常使用的文件,没有本质区别,操作系统提供API打开、读取、改写。 可用xxd查看可执行文件。
xxd
打开程序的执行:Trace(追踪)。 重要的工具:strace System call trace
execve("./a.out", ["./a.out"], 0x7ffc30b64060 /* 30 vars */) = 0 write(1, "\33[01;31mHello, OS World\33[0m\n", 28Hello, OS World) = 28 exit(1) = ? +++ exited with 1 +++
所有的软件其实都是计算、执行系统调用……
Disassembly of section .text:
0000000000000000:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: 5d pop %rbp
a: c3 ret
┌────────────────────────────────────────────────────────┐ │ 0x401000 push %rbp │
│ 0x401001 <main+1> mov %rsp,%rbp │
│ 0x401004 <main+4> mov $0x0,%eax │
│ 0x401009 <main+9> pop %rbp │
│ > 0x40100a <main+10> ret │
│ 0x40100b add %al,(%rax) │
│ 0x40100d add %al,(%rax) │
│ 0x40100f add %al,(%rax) │
└────────────────────────────────────────────────────────┘
native process 863 In: main L?? PC: 0x40100a
(gdb) si
0x0000000000401001 in main ()
0x0000000000401004 in main ()
0x0000000000401009 in main ()
0x000000000040100a in main ()
(gdb) p $rsp
$1 = (void *) 0x7fffffffdd20
(gdb) x $rsp
0x7fffffffdd20: 0x00000001
(gdb)
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:
怎么写一个非递归的汉诺塔?
编译器做的其实也是把high level代码翻译成指令的行为。
理解编译器
有两种状态机:
操作系统上的软件
与日常使用的文件,没有本质区别,操作系统提供API打开、读取、改写。 可用
xxd
查看可执行文件。打开程序的执行:Trace(追踪)。 重要的工具:strace System call trace
所有的软件其实都是计算、执行系统调用……