按照链接2在编译FreeNOS的过程中,发现由于FreeNOS的实现是一个32位的操作系统,而且其C++代码中内嵌了很多的汇编指令,因此在64位计算机上直接编译会报错:
Error: unsupported instruction ‘mov’
定位到对应的文件${FreeNOS_HOME}/lib/libarch/intel/IntelCore.h看到:
inline u64 timestamp()
{
u64 low = 0, high = 0;
asm volatile ("rdtsc\n"
"movl %%eax, %0\n"
"movl %%edx, %1\n" : "=r"(low), "=r"(high));
return (high << 32) | (low);
}
这段代码通过调用timestamp()获得处理器的时间戳计数器的值,asm
表示內联汇编,volatile
表示告诉编译器不要对这段汇编指令做优化;
rdtsc
意为read TSC Register(读取TSC寄存器)
,从Pentium开始,多数80x86处理器都引入了TSC寄存器,一个用于时间戳计数器的64位寄存器,每个时钟周期CLK会使TSC中的值自增1,例如:CPU主频1MHz,那么TSC在1s内增加1000000;
rdtsc
指令把TSC寄存器的低32位存放在eax寄存器中,高32位存放在edx中;
movl %%eax, %0
表示将eax寄存器的值输出到参数0(low),此时eax中保存了TSC的低32位;
movl %%edx, %1
表示将edx寄存器的值输出到参数1(high),此时edx中保存了TSC的高32位;
注意:这里movl表示传送32位长度的数据(long),还有movw传送16位数据(word),movb传送8位数据(byte),然而在64位计算机上由于指令集的区别,编译器按64位指令集来编译汇编文件时,会导致无法识别32位指令的情况。
So,我们需要告诉编译器,请用32位指令集来编译汇编文件。
(1) 对于gcc,添加编译选项
-m32
,例如:$gcc -m32 -c test.c -o test
(2) 对于汇编工具as,添加编译选项--32
,例如:$as --32 test.s -o test.o
(3)对于链接工具ld,添加编译选项-m elf_i386
,例如:$ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o test test.o
,这里用-lc
是因为我在汇编文件中用了prinft
注意:由于用到了32位构建工具包,如果编译过程有找不到对应文件的问题,可以试试一下命令安装工具包:$sudo apt-get install libc6-dev-i386
或者$sudo apt-get install gcc-multilib g++multilib
这里附上汇编文件test.s
.section .data
output:
.asciz "The value is %d\n"
values:
.int 10,15,20,25,30,35,40,45,50,55,60
.section .text
.global _start
_start:
nop
movl $0, %edi
loop:
movl values(,%edi,4), %eax
pushl %eax
pushl $output
call printf
addl $8, %esp
inc %edi
cmpl $11, %edi
jne loop
movl $0, %ebx
movl $1, %eax
int $0x80
参考 链接3,在${FreeNOS_HOME}/SConstruct文件中修改环境变量:
build_env = target
Export('build_env')
build_env.Append(CCFLAGS='-m32 -Wno-cpp -Wno-unused-variable -Wno-sign-compare')
最后在${FreeNOS_HOME}目录下执行$scons iso
,成功!
这样就可以在64位计算机上跑FreeNOS啦!