跳转至

南京大学操作系统

Abstract

jyy os

Info

jyyos

绪论

Lec0 操作系统上的程序

  • 如何构建最小的hello world:如果采用-static 会复制 libc,那么如果采用gcc -cld链接会失败,下面是gcc -c产生的elf文件的汇编代码
1
2
3
4
5
6
#include <stdio.h>

int main()
{
    printf("hello,world\n");
}

image-20240530145027647

直接采用ld链接,会发现os上的程序需要libc中的==_start()函数==调用main函数,所以尝试直接将函数声明为_start()并且去除printfputs的调用,因为没有库函数定义puts

1
2
3
void _start() {

}
1
2
3
ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
ld: main.o: in function `main':
main.c:(.text+0x13): undefined reference to `puts'

然后发生了segmentation fault,但是将_start()的函数体改为while(1)就能消除bug

image-20240530150819085

原因

​ 使用GDB查看哪条指令导致了段错误:发现是ret指令导致,ret指令的语义是就是将栈顶存储的ra赋值给pc,然后出栈,即stack[rsp] -> rip; rsp = rsp + 8;出错的原因可能是rsp指向的堆栈区不合法,查看后排除,但是发现rip的值会被赋值为1,地址为0x1的内存不能被访问,导致段错误,所以解决方法就是死循环不返回。

image-20240530152310636

发现

纯粹的计算指令无法让状态机顺利结束,需要调用syscall让系统停下来;由下面的代码发现,syscall在执行前需要根据手册对对应的寄存器赋值,即准备好需要的系统调用参数,把控制权交给操作系统,但是syscall的实现在libc中,不方便直接链接。所以最小的hello world就是模仿syscall,自己实现libc

1
2
3
4
5
#include <sys/syscall.h>

int main() {
  syscall(SYS_exit, 42);
}

image-20240530153730597

最小的hello,world实现如下:

坑点

注意这个文件为hello.S,后缀为大写的S,然后使用gcc -c hello.S && ld hello.o生成可执行文件

#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:

并发

虚拟化