• 在64位主机上编译产生32位的目标代码


       今天又看CS630[1]的Chapter 15,发现里头的一个例程manydots.s无法正常编译。
    $ gcc manydots.s -o manydots
    /tmp/ccIvmRVT.o: In function `_start':
    (.text+0x0): multiple definition of `_start'
    /usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../../lib/crt1.o:(.text+0x0): first defined here
    /usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../../lib/crt1.o: In function `_start':
    (.text+0x20): undefined reference to `main'
    collect2: ld returned 1 exit status
    $ sed -i -e "s/_start/main/g" manydots.s
    $ gcc manydots.s -o manydots
    $ ./manydots
    Segmentation fault
    $ file manydots
    manydots:
    ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked
    (uses shared libs), for GNU/Linux 2.6.8, not stripped
       
    通过上面的实验,首先依据提示发现_start有multiple
    definition,所以依据自己的经验,把里头的_start符号替换成main。由于用gcc编译时默认的程序入口是main,而不是
    _start。资料[2]告诉我们_start是真正的程序入口,可是这个真正的入口是gcc默认链接到我们的可运行文件里的,假设我们这里又设置一个
    _start符号,那就是multiple
    definition了(你能够通过gcc的-S选项编译一个C语言程序产生汇编代码,看看汇编代码的程序入口,刚好是main,关于谁是真正的程序入
    口,你能够看看资料[2])。
        那改动了_start为main后,可以正常编译,但为什么还出现segmentation fault呢?原因是源码mangdots.s是为32为平台写的,而我用的处理器是64位的,而且安装了64位的Ubuntu/Linux。
    [color="black"]$ cat /proc/cpuinfo | grep "model name"
    model name    : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+
    model name    : AMD Athlon(tm) 64 X2 Dual Core Processor 4200+
    $ uname -a
    Linux falcon 2.6.26-1-amd64 #1 SMP Thu Aug 28 11:13:42 UTC 2008 x86_64 GNU/Linux

       
        依据资料[3,4,5],我们发现,64位平台跟32位平台有非常大的不同,包含參数传递方式,指令集都有非常大的变化,那怎么可以让它正常执行呢?利用
    gcc的-m32參数编译产生32位的目标代码,而不是64位的目标代码,由于32位的目标代码能够执行在64位的主机上。
    $ gcc -m32 manydots.s -o manydots
    $ ./manydots
    How many dots do you want to see? 10
    ..........
    $ file manydots
    manydots:
    ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically
    linked (uses shared libs), for GNU/Linux 2.6.8, not stripped
    能够看到,这样就okay了。
        实际上,我们还能够分步来做:先汇编,后链接。这样能够降低目标代码的大小,先看看原来的大小。
    [color="black"]$ wc -c manydots
    6495 manydots

       
        我们分步汇编、链接:
    [color="black"]// 这个时候是须要一个默认的_start入口的,假设不指定,会默认设置一个程序入口地址,由于这个时候没有人给我们设置一个真正的入口_start了。
    $ sed -i -e "s/main/_start/g" manydots.s
    $ as --32 manydots.s -o manydots.o
    $ ld -m elf_i386 manydots.o -o manydots
    $ wc -c manydots
    1026 manydots
    $ echo "6495-1026" | bc
    5469
    $ ./manydots
    How many dots do you want to see? 10
    ..........

        能够发现,这样也能够正常工作,只是目标降低了5469个字节。为什么会有这种效果呢?资料[2]给出了具体的解释,假设感兴趣,能够研究一下。
        对了,“as --32 manydots.s -o manydots.o”能够直接用“$ gcc -m32 -c manydots.s -o manydots.o” 来做,他们两个实际上做了同一个事情,你能够通过gcc的--verbose查看:
    $ gcc --verbose -m32 -c manydots.s -o manydots.o
    Using built-in specs.
    Target: x86_64-linux-gnu
    Configured
    with: ../src/configure -v --with-pkgversion='Debian 4.3.1-9'
    --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs
    --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
    --enable-shared --with-system-zlib --libexecdir=/usr/lib
    --without-included-gettext --enable-threads=posix --enable-nls
    --with-gxx-include-dir=/usr/include/c++/4.3 --program-suffix=-4.3
    --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc
    --enable-mpfr --enable-cld --enable-checking=release
    --build=x86_64-linux-gnu --host=x86_64-linux-gnu
    --target=x86_64-linux-gnu
    Thread model: posix
    gcc version 4.3.1 (Debian 4.3.1-9)
    COLLECT_GCC_OPTIONS='-v' '-m32' '-c' '-o' 'manydots.o' '-mtune=generic'
    as -V -Qy --32 -o manydots.o manydots.s
    GNU assembler version 2.18.0 (x86_64-linux-gnu) using BFD version (GNU Binutils for Debian) 2.18.0.20080103
    COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/
    LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/4.3.1/32/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/32/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../../lib32/:/lib/../lib32/:/usr/lib/../lib32/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/:/usr/lib/gcc/x86_64-linux-gnu/4.3.1/../../../:/lib/:/usr/lib/
    COLLECT_GCC_OPTIONS='-v' '-m32' '-c' '-o' 'manydots.o' '-mtune=generic'
        最后总结一下,在64位主机上编译产生32位目标代码的办法:
        一、办法一:直接通过gcc汇编、链接
            1、确保不要有反复的_start入口,把_start替换成main
           2、用gcc加上-m32參数进行汇编和链接
        二、办法二:分步汇编、链接
            1、汇编的时候,用gcc加上-m32參数或者用as加上--32參数。
            2、在链接的时候,用ld加上-m elf_i386參数。
    [1] CS630 on ubuntu with qemu
    http://oss.lzu.edu.cn/blog/blog.php?/do_showone/tid_1808.html
    [2] 为你的可运行文件“减肥”
    http://oss.lzu.edu.cn/blog/blog.php?do_showone/tid_1547.html
    [3] GCC在AMD64平台下的參数传递
    http://hi.baidu.com/bluebanboom/blog/item/381959af65ff36fbfaed5068.html
    [4] Intel的64位扩展技术简单介绍
    http://www.njyangqs.com/hardware/ia-32etech.htm
    [5] AMD64 Architecture Tech Docs
    http://www.amd.com/us-en/Processors/DevelopWithAMD/0
    ,,30_2252_739_7044,00.html
                   
                   
                   

    本文来自ChinaUnix博客,假设查看原文请点:http://blog.chinaunix.net/u2/76848/showart_1403907.html

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    编译出错 "undefined reference to"

    最终在GCC里開始编译了,HoHo~  Make一下,刚刚才高兴了一阵子,又报错了    郁闷~ :

    klib.c:(.text+0xda): undefined reference to `__stack_chk_fail'

    貌似是说 _stack_chk_fail 我们有一个没有定义的函数引用?但是我们没实用过这个函数啊?左思右想,看来似乎不是我们程序的问题了。来看看网上怎么说的:
    一些版本号的gcc编译时常会出现 undefined reference to `__stack_chk_fail'的错误,能够在makefile的CFLAGS中加入-fno-stack-protector一项。
    恩,那我们就在我们的配置文件MakeFile中CFLAGS中加上一句
    CFLAGS  = -I ./include/ -c -fno-stack-protector
    这里我把后面的一个错误也顺便贴上了。错误例如以下:
    undefined reference to `memset'
    这个在cflags里面再加上一个參数 CFLAGS  = -I ./include/ -c -fno-stack-protector  -minline-all-stringops

    这样编译就通过了。出现这些问题大都是是因为gcc的个别版本号默认设置,比方我用的gcc 4.13+ubuntu 7.10 就有可能出现这个问题。



    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    Ubuntu Linux上编译kernel出错__stack_chk_fail



    在顶层的Makefile里找到CFLAGS然后加入-fno-stack-protector标志!!!

  • 相关阅读:
    Redis Hashes 巧用sort排序
    Redis 压缩存储的配置
    计算
    关于时间大小判断的坑和网上工具类的看法
    Mysql中字段类型之时间戳大坑2
    Mysql中字段类型之时间戳大坑
    Spring和springmvc父子容器注解扫描问题详解
    JXL导出Excel工具类
    Maven学习
    MySQL之账户管理
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4187257.html
Copyright © 2020-2023  润新知