ubuntu18.04 下高版本gcc实践操作系统时出现的问题
ub18.04 的gcc 版本本身就高,所以在实践 自制一个64位操作系统 中的实验时,容易出现不少代码在 centos6 能正常编译,到了ub18 上编译不通过,书的作者本人 似乎只是建议读者 采用他自己使用的centos6上实践来避免这个问题,如下截图
- 这个问题在其他地方也有提到,比如:
https://stackoverflow.com/questions/54916731/answer/submit
I'm using gcc to compile a printing function. But met the following 2 problems:
Whenever I apply a local array type variable, the linker would report \
and error of "undefined reference to `__stack_chk_fail'"
When I'm using "inline" to define a function, \
it report an error of "undefined reference to `strlen'"
My platform is Ubuntu 18.04, and gcc version is 7.3.0.
- 我自己 ub18 上实践时的情况如下:
zj@zj-virtual-machine:~/bochs_prj/64os/4-3/kernel$ make
gcc -E head.S > head.s
as --64 -o head.o head.s
gcc -mcmodel=large -fno-builtin -m64 -c main.c
gcc -mcmodel=large -fno-builtin -m64 -c printk.c
ld -b elf64-x86-64 -z muldefs -o system head.o main.o printk.o -T Kernel.lds
printk.o: In function `number':
printk.c:(.text+0x4a6): undefined reference to `__stack_chk_fail'
printk.o: In function `vsprintf':
printk.c:(.text+0x866): undefined reference to `strlen'
printk.o: In function `color_printk':
printk.c:(.text+0x13f2): undefined reference to `__stack_chk_fail'
Makefile:20: recipe for target 'system' failed
make: *** [system] Error 1
吐槽
我自己在网上查了不少,反正目前是没有完整解决,有大佬通过 编译链接 让链接器能够正常找到strlen
这个符号的话,告诉我一下,不胜感激。
反正,做实验无非是让程序能正常跑起来,所以这里我采用一个折中的办法,来解决上面提到的问题。对于第一个问题的话:
printk.c 开启-fno-stack-protector 能解决 undefined reference to `__stack_chk_fail' 这个问题
具体见下面的 Makefile
all: system
objcopy -I elf64-x86-64 -S -R ".eh_frame" -R ".comment" -O binary system kernel.bin
system: head.o main.o printk.o
ld -b elf64-x86-64 -z muldefs -o system head.o main.o printk.o -T Kernel.lds
head.o: head.S
gcc -E head.S > head.s
as --64 -o head.o head.s
main.o: main.c lib.h
gcc -static -mcmodel=large -fno-builtin -m64 -c main.c -fno-stack-protector
printk.o: printk.c lib.h
gcc -static -mcmodel=large -fno-builtin -m64 -c printk.c -fno-stack-protector
clean:
rm -rf *.o *.s~ *.s *.S~ *.c~ *.h~ system Makefile~ Kernel.lds~ kernel.bin
关于 strlen
的问题,既然找不到这个符号,本来这个符号的定义是在这个头文件里面的(#include "lib.h")
,所以为了偷懒,不要内联优化这些,直接把这个内联的函数给剪切到printk.c
这个函数里面,取消内联,直接编译进去,这样就不会出现找不到这个函数的定义了。部分代码见如下:
$cat printk.c
#include <stdarg.h>
#include "printk.h"
#include "lib.h"
#include "linkage.h"
int __strlen(char * String) //here !!!! 这里我把这个函数名全部统一改成了__strlen
{
register int __res;
__asm__ __volatile__ ( "cld \n\t"
"repne \n\t"
"scasb \n\t"
"notl %0 \n\t"
"decl %0 \n\t"
:"=c"(__res)
:"D"(String),"a"(0),"0"(0xffffffff)
:
);
return __res;
}
...........
run 一下,效果如图
后记
如果后面再遇到问题,我可能也要转战 centos6 ,不然解决这些问题 还是挺费时间的。