FreeNOS学习,在Ubuntu16.04的64位计算机上编译32位汇编文件,在SConstruct中添加编译选项

  • 日期:2018年4月29日
  • 背景:最近在学习Github上的一个开源C++写的操作系统微内核项目FreeNOS,各种宏内核中的服务作为一个独立的services在微内核中,基于消息的通信方式,除了能够学习到操作系统的实现,还有常见的OOP设计模式、代码风格、注释和doxygen
  • 链接:
    1. github 项目地址
    2. 编译FreeNOS
    3. Scons浅入浅出

Error: unsupported instruction ‘mov’

按照链接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 

$./test执行结果:
FreeNOS学习,在Ubuntu16.04的64位计算机上编译32位汇编文件,在SConstruct中添加编译选项_第1张图片

在${FreeNOS_HOME}/SConstruct中添加编译选项-m32

参考 链接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啦!

你可能感兴趣的:(linux编程,操作系统)