直接说重点:
在文档中的
3. Bare-Metal 上的 C 程序
其中的
3.1. 链接
有以下命令
$ ld -melf_x86_64 -N -Ttext-segment=0x00100000 -o build/hello-x86_64-qemu.o \
main.o say.o am-x86_64-qemu.a klib-x86_64-qemu.a
容易发现这个 am-x86_64-qemu.a和 klib-x86_64-qemu.a是哪里来的?
查看abstract-machine的根目录的Makefile其中有
ARCHIVE = $(WORK_DIR)/build/$(NAME)-$(ARCH).a
可以知道肯定是和这个文件有关,这个命令就是.a文件的来源尝试使用命令
root@87f95c70b3ff:/home/newos/os-workbench/abstract-machine# make AM_HOME=. ARCH=x86_64-qemu
Makefile:40: *** Nothing to build. Stop.
说明有问题,查看了所有的makefile之后发现只要进入到子文件中就可以
root@87f95c70b3ff:/home/newos/os-workbench/abstract-machine/am# make AM_HOME=./.. ARCH=x86_64-qemu
# Building am-image [x86_64-qemu]
+ AS src/x86/qemu/start64.S
+ AS src/x86/qemu/trap64.S
+ CC src/x86/qemu/trm.c
+ CC src/x86/qemu/cte.c
+ CC src/x86/qemu/ioe.c
+ CC src/x86/qemu/vme.c
+ CC src/x86/qemu/mpe.c
# Building am-archive [x86_64-qemu]
+ AR -> build/am-x86_64-qemu.a
# Building klib-archive [x86_64-qemu]
+ CC src/stdio.c
+ CC src/stdlib.c
+ CC src/string.c
+ CC src/cpp.c
+ CC src/int64.c
+ AR -> build/klib-x86_64-qemu.a
+ LD -> build/am-x86_64-qemu.elf
x86_64-linux-gnu-ld: /home/newos/os-workbench/abstract-machine/am/build/x86_64-qemu/src/x86/qemu/trm.o: in function `call_main':
trm.c:(.text+0xbb): undefined reference to `main'
make: *** [../Makefile:131: /home/newos/os-workbench/abstract-machine/am/build/am-x86_64-qemu.elf] Error 1
然后在当前目录下的bulid下就可以找到对应的.a文件
如果直接使用文档中的命令链接这两个文件还是会有问题
ld -melf_x86_64 -N -Ttext-segment=0x00100000 -o build/hello-x86_64-qemu.o \
main.o say.o am-x86_64-qemu.a klib-x86_64-qemu.a
ld: say.o: in function `say':
say.c:(.text+0x11): undefined reference to `putchar'
putchar这个应该是C语言中的一个功能,打算在没有环境的am上运行显然是不可能的,检查代码,发现
// say.c void putch(char ch); int putchar(int ch); void say(const char *s) { for (; *s; s++) { #ifdef __ARCH__ putch(*s); // AbstractMachine,没有 libc,调用 TRM API 打印字符 #else putchar(*s); // 操作系统,调用 libc 打印字符 #endif } }
也就是说,我们之前的编译没有__ARCH__这个宏,所以需要重新编译say.o
root@87f95c70b3ff:/home/os-workbench/abstract-machine/src# rm say.o
root@87f95c70b3ff:/home/os-workbench/abstract-machine/src# gcc -c -D__ARCH__ -O2 -o say.o say.c
这样出来的say.o就符合我们的需求了,
再次进行编译
root@87f95c70b3ff:/home/os-workbench/abstract-machine/src# ld -melf_x86_64 -N -Ttext-segment=0x00100000 -o build/hello-x86_64-qemu.o main.o say.o am-x86_64-qemu.a klib-x86_64-qemu.a
通过
但是这个还是没有完成整个实验,后续的命令中
( cat abstract-machine/am/src/x86/qemu/boot/mbr \ head -c 1024 /dev/zero \ cat build/hello-x86_64-qemu.o ) \ > /tmp/hello/build/hello-x86_64-qemu
其实是找不到mbr的文件的,暂时还没有方法解决,也希望有解决的小伙伴帮忙一下
当天更新:
找到mbr了,先看了一下boot目录里面的文件觉得有可能是mbr,但是输出是bootloader.o有点不明所以,但是其中有一个py文件,查看内容如下:
import os, sys, pathlib, subprocess
f = pathlib.Path(sys.argv[1])
try:
objcopy = os.getenv('CROSS_COMPILE', '') + 'objcopy'
data = subprocess.run(
[objcopy, '-S', '-O', 'binary', '-j', '.text', f, '/dev/stdout'],
capture_output=True).stdout
assert len(data) <= 510
data += b'\0' * (510 - len(data)) + b'\x55\xaa'
f.write_bytes(data)
except:
f.unlink()
raise
可以看到里面有一个是往里面添加了一个x55xaa,这个不就是mbr的结尾吗,所以我更加坚定了bootloader.o就是我要的mbr的想法,直接mv重命名为mbr,但是后面还有坑,我在执行
( cat abstract-machine/am/src/x86/qemu/boot/mbr \ head -c 1024 /dev/zero \ cat build/hello-x86_64-qemu.o ) \ > /tmp/hello/build/hello-x86_64-qemu
的时候,会报错cat没有c这个参数,试了各种办法都还是这样,我只能把它拆成三个部分运行
root@87f95c70b3ff:/home/os-workbench/abstract-machine# cat am/src/x86/qemu/boot/mbr >> hello-x86_64-qemu
root@87f95c70b3ff:/home/os-workbench/abstract-machine# head -c 1024 /dev/zero >> hello-x86_64-qemu
root@87f95c70b3ff:/home/os-workbench/abstract-machine# cat build/hello-x86_64-qemu.o >> hello-x86_64-qemu
应该没有什么区别把,总之我的结果是出来了
root@87f95c70b3ff:/home/os-workbench/abstract-machine# file hello-x86_64-qemu
hello-x86_64-qemu: DOS/MBR boot sector; partition 1 : ID=0x29, active 0xe4, start-CHS (0x38,141,20), end-CHS (0xc0,249,49), startsector 2868107145, 3296970219 sectors
后面的结果也都差不多,真不容易啊,但是靠自己解决问题还是挺有成就感的