实验内容:在Linux下用汇编写Hello, World!;进一步,汇编和C同时使用;从loader到kernel内核,把kernel内核加载到内存;将控制权交给kernel内核;跳入保护模式,并显示内存的使用情况。
实验步骤
①创建hello.asm
文件
②编译链接(每执行一步都用ls
命令查看文件的增加情况)
> ls
hello.asm
> nasm -f elf hello.asm -o hello.o # 指定输出文件的格式为ELF格式,hello.o为01文件
> ls
hello.asm hello.o
> ld -s hello.o -o hello # 将 hello.o与系统库文件连接,并生成可执行文件 hello
! ①执行最后一条指令时报错 \textcolor{red}{!①执行最后一条指令时报错} !①执行最后一条指令时报错
上面为Linux系统下执行汇编文件的操作过程(编译 链接 执行)
本例重点是汇编代码和C代码之间相互调用
实验步骤
②将bar.o
和foo.o
文件链接为可执行foobar
文件
! ②执行指令再次出现不兼容问题 \textcolor{red}{!②执行指令再次出现不兼容问题} !②执行指令再次出现不兼容问题
③执行foobar
文件
./foobar
重点就是关键字global
和extern
!!!!!!!!!!
global
是一个汇编符号,用于声明一个全局变量,当一个变量被声明为global时,它可以被程序中的任何模块访问extern
是关键字,用于声明一个变量,表明这个变量并不是在这里声明的,而是在别的文件中定义的。使用 extern
关键字可以让多个文件共享同一个变量ELF header
:是一个描述文件本身的结构体,它包含了文件的基本信息,如文件类型、机器类型(目标文件所运行的机器平台)、入口地址、程序头表和节头表等信息。Program header table
:段表,描述一个段在文件中的位置、大小以及它被放进内存后所在的位置和大小在Linux系统中,当一个ELF文件被加载到内存中时,操作系统会根据Program header table中的信息将文件中的各个段映射到内存中的相应位置,并设置相应的权限。这样,程序就可以正确地执行了
Loader的工作:
文件介绍:
fat12hdr.inc
:包含了FAT12文件系统的头文件,其中定义了FAT12文件系统的各种数据结构和常量boot.asm
:装入引导扇区的启动程序loader.asm
:将内核放进内存第一次运行:
①创建新软盘a.img
②将boot.bin
装载到引导扇区:
nasm boot.asm -o boot.bin
dd if=boot.bin of=a.img bs=512 count=1 conv=notrunc
③将kernel.bin
装载到软盘
nasm -f elf -o kernel.o kernel.asm
ld -m elf_i386 -s -o kernel.bin kernel.o
sudo mount -o loop a.img /mnt/floppy/
sudo cp kernel.bin /mnt/floppy/ -v
sudo umount /mnt/floppy/
loader没装进去
代码改变:
第三章中程序由BIOS或DOS加载,描述符的段基址都是运行时计算后填入相应的位置,我们不知道段地址,于是也就不知道程序运行时在内存中的位置
现在Loader由我们自己加载,文件中定义段地址为BaseOfLoader
即,在loader中增加跳入保护模式的代码
实验步骤
我们要做的工作是根据内核(ELF文件格式)的 Program header table 的信息进行类似下面这个C语言语句的内存复制
memcpy(p_vaddr, BaseOfLoaderPhyAddr + p_offset, p_filesz);
函数解释:从源内存地址的起始位置开始拷贝若干个字节到目标内存地址
参数解释:
实验步骤
①编译链接程序时,将程序入口地址改为0x30400
nasm -f elf -o kernel.o kernel.asm
ld -m elf_i386 -s -Ttext 0x30400 -o kernel.bin kernel.o
内核放置函数为
memcpy(3000h, 9000h + 0, 40Dh);
②查看kernel.bin
的内容
xxd -u -a -g 1 -c 16 kernel.bin
呃呃呃
原因分析
输入文件hello.o
编译为 i386 架构,与输出架构 i386:x86-64 不兼容。这可能是因为编译器和链接器正在尝试将不同架构的目标文件进行链接,导致链接失败。
解决办法
更改输入指令为
ld -m elf_i386 -s -o hello hello.o
其中-m 选项指定目标文件的架构为 elf_i386,与输入的hello.o
文件架构匹配
参考
这是一个连接
原因分析
错误提示是由于foo.o
和bar.o
的架构不同,foo.o
是 i386 架构,而 bar.o
是 x86-64 架构
解决办法
将文件全部编译为i386框架下的.o
文件,再进行链接,即执行下述指令
nasm -f elf -o foo.o foo.asm
gcc -m32 -c bar.c -o bar.o
ld -m elf_i386 -s -o foobar foo.o bar.o