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_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啦!

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Ubuntu 16.04 上建立交叉编译环境,可以按照以下步骤进行: 1. 安装交叉编译工具链 在命令行执行以下命令: ``` sudo apt-get update sudo apt-get install gcc-arm-linux-gnueabihf ``` 这将安装 ARM 架构的交叉编译器。如果你要编译其他架构的内核,需要安装相应的交叉编译器。 2. 下载内核代码 可以从官网下载 Linux 内核代码,也可以使用 git 命令从官方仓库下载代码。例如,从官方仓库下载 Linux 5.14.6 版本的代码: ``` git clone --depth 1 --branch v5.14.6 git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git ``` 3. 配置编译选项 进入内核代码的目录,执行以下命令: ``` make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig ``` 这将打开内核配置界面,在这里可以选择编译选项,包括编译成模块还是静态链接,支持哪些硬件等等。 4. 编译内核 执行以下命令编译内核: ``` make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4 ``` 其 -j4 表示使用 4 个线程并行编译,可以根据自己的电脑配置调整。 5. 安装内核 执行以下命令安装内核: ``` sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=<path_to_rootfs> modules_install ``` 其 <path_to_rootfs> 是根文件系统的路径,可以将内核模块安装到对应的目录下。 6. 生成镜像 执行以下命令生成内核镜像: ``` make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage ``` 这将生成 zImage 文件,可以使用该文件启动 ARM 设备。 以上就是在 Ubuntu 16.04 上建立交叉编译环境,并配置编译内核的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值