当前位置: 首页 > 工具软件 > GNU toolchain > 使用案例 >

编译GNU toolchain for ARM 笔记

韦翰音
2023-12-01

构建自己的arm-linux toolchain:
生成工具链目录结构:
/usr/armtools
  `----arm-linux   目标平台相关内容
  | `----bin   gcc内部使用的编译/连接工具
  | `----lib   gcc的内部库/c++ 库
  | | `----ldscripts  ld的连接脚本
  | `----target-root  目标平台根目录
  |   `----etc   目标平台配置(ld.so.cache)
  |   `----lib   目标平台glibc库
  |   `----usr
  |      `----include  glibc头文档
  `----bin   + arm-linux-gcc,arm-linux-ld,...
  `----include
     `----c++   c++ 标准头文档
  `----lib
  | `----gcc   gcc内部库核心cc1,collect2
  |   `----...
  `----libexec
  | `----gcc   gcc内部使用的辅助工具
  |   `----...
  `----man   man for gcc/glib/binutils
  `----info   info for gcc/glib/binutils
  `----share   Locale等
该目录结构由binutils, gcc, glibc的目录复合而成,可变性很差, 稍有差错就可能导致工具链无法使用。 目录的结构由以下几个配置参数决定:
--prefix=chain/root   工具链根目录, 缺省为/usr/local
  虽然gcc/binutils支持multi-lib方式,能够使用/usr/local作为工具链根目录而不和本地gcc发生冲突, 但glibc并不支持这一特性。因此一般使用prefix把根目录指定到某一特定目录,比如/usr/armtools。
  但对于glibc,此目录同时也是glibc的库文档工作的时候(在target上运行应用程式的时候)寻找文档所用路径,因此应该配置为缺省的/usr,而使用install_root来指定安装路径。

--with-sysroot   目标板根目录。gcc将由此开始按照标准linux目录结构寻找编译所需的头文档和库。binutils现在对此参数支持还不是很好,假如不配合make时使用LIB_PATH,ld会无法为so文档找到其所需的其他so文档。
LIB_PATH    辅助指定库所在路径
install_root    指定glibc安装路径。倘若不指定此参数,prefix=/usr的情况make install会导致系统本地glibc库被覆盖。

1 Binutils:
GNU二进制文档处理工具,核心工具为ld和as。构造arm-linux-gcc时需要用到arm-linux-ld
和arm-linux-as来生成g++的arm-elf库,构造glibc时同样需要用到。
binutils是toolchain的基础,假如配置不正确,会给后来的编译带来诸多问题。
./configure --prefix=/usr/armtools --target=arm-linux --with-sysroot=/usr/armtools/arm-linux/target-root
make LIB_PATH=/usr/armtools/arm-linux/target-root/lib tooldir=/usr/armtools
make install
   /usr/armtools
  |----arm-linux  供GCC/Binutils内部使用
  |  |----bin   内部命令 ld,as...
  |  `----lib   内部库
  |     `----ldscripts  ld的连接脚本。假如用到的so库中使用了其他so库,则搜索路径在这里指定
  |----bin  供用户使用的命令 arm-linux-*  
  |----info  info
  |----lib  用户使用的库
  `----man  man
     `----man1  binutils manual
make需要autoconf, automake, m4, flex, yacc, gettext支持。
假如make时出现:/bin/bash: no command not found一类的错误时,需要更新gettext,或configure时加上 --disable-nls 关闭本地化语言支持。
arm-linux-ld将会/usr/armtools/arm-linux/lib中寻找连接时使用的.so文档。假如很难找到,则在glibc编译完成后,gcc无法编译动态链接的文档,提示:
  warning: ld-linux.so.2, needed by /libc.so.6, not found
唯有同时指定--with-sysroot 和 LIB_PATH可解决此问题。

binutils2.15 同 gcc3.4.3 + glibc2.3.2面向ARM时冲突。该冲突尚未解决(2005.3.1)
2 Kernel Source
Linux 内核源代码的头文档是编译glibc必需的。 获取Linux初始源代码并针对架构打上补丁,以Xscale为例:
获取:
  linux-2.4.19.tar.gz  初始源代码
  patch-2.4.19-rmk7.bz2  针对ARM的补丁
  diff-2.4.19-rmk7-pxa2.gz 针对Xscale的补丁

打补丁:
  tar -xzf linux-2.4.19.tar.gz
  cd linux-2.4.19/
  bzcat ../patch-2.4.19-rmk7.bz2 | patch -p1
  zcat ../diff-2.4.19-rmk7-pxa2.gz | patch -p1
配置内核并配置头文档依赖:
  make ARCH=arm menuconfig
   选择Processor Type 为 PXA210/250,
   选择适当的研发平台
   保存退出
  make dep   
复制header:
  mkdir /usr/armtools/arm-linux/usr
  mkdir /usr/armtools/arm-linux/usr/include
  cp -rD linux-2.4.19/include/arm-asm/ /usr/armtools/arm-linux/target-root/usr/include/
  cp -rD linux-2.4.19/include/linux/ /usr/armtools/arm-linux/target-root/usr/include/
在/toolschain/rootdir/arm-linux下建立了include目录
  
make dep 会需要arm-linux-gcc存在...
3 GCC-Core
GCC本身的编译分为两个部分. 首先是建立运行在Host平台上的一系列交叉编译工具arm-linux-gcc/g++/java..., 另一个是编译特定语言写成的应用程式时所需要的静态库(.a)和动态库(.so)文档. 例如c++的libstdc++.*和java的libjava.*. c本身的库文档glibc(libc.*)需要单独编译。
由于g++和java等编译器使用glibc,因此,在完全没有编译环境的情况下,只能够先编译gcc-core(gcc),然后利用生成的gcc编译glibc, 最后生成其他语言的编译器。
获取:
  gcc-core-3.4.3.tar.bz2  GNU C Core &Compiler
编译时按照编译需要,最好将源代码和生成的OBJ分开放置:
  tar -xjf gcc-core-3.4.3.tar.bz2
  mkdir gccobj
  cd gccobj

由于现在没有glibc, 需要修改编译条件,使编译过程中不使用glibc:
  vi gcc-3.4.3/gcc/config/arm/t-linux
  将
   TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC
  改为
   TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC -Dinhibit_libc -D__gthr_posix_h
配置并编译:
  export PATH=$/toolchain/rootdir/bin:$PATH
  ../gcc-3.4.3/configure --prefix=/usr/armtools --target=arm-linux --with-sysroot=/usr/armtools/arm-linux/target-root --enable-languages=c --disable-threads -disable-shared
  make
  make install
配置参数说明:
  --prefix   gcc安装的根目录,缺省为/usr/local
  --target   目标平台
  --without-headers  不使用头文档。gcc编译的时候会引用目标平台的linux和libc头文档。
      指定此选项避免出现"stdio.h: file not found"一类的错误
  --enable-languages=c  只生成c编译器
  --disable-threads  gcc使用线程来提高编译速度,但现在还没有Target的glibc
  --disable-shared  生成Target平台的so文档需要glibc,现在还没有

4 Glibc
假如需要编译在target上运行的用户空间程式,则glibc是必需的。
获取:
  glibc-2.3.2.tar.gz
  glibc-linuxthreads-2.3.2.tar.bz2
配置编译目录:
  tar -xzf glibc-2.3.2.tar.gz
  cd glibc-2.3.2
  tar -xjf ../glibc-linuxthreads-2.3.2.tar.bz2
  cd ..
  mkdir glibcobj
配置并编译:
  cd glibcobj
  BUILD_CC=gcc CC=arm-linux-gcc AR=arm-linux-ar RANLIB=arm-linux-ranlib ../glibc-2.3.2/configure --build=i386-linux --host=arm-linux --prefix=/usr --enable-add-ons --with-headers=/usr/armtools/arm-linux/target-root/usr/include/
  make
  make install install_root=/usr/armtools/arm-linux/target-root
修改Glibc为ARM编译的ld脚本bug:
  去掉.../target-root/usr/lib中*.so文档中的***BUG.....***一行
*** configure: error: cannot compute sizeof (long double)

假如不指定--build,configure会以为在进行本地编译,从而运行测试程式,导致配置不成功。这应该是glibc2.3.2的bug
*** "crti.S:96: Error: can’t resolve : `_GLOBAL_OFFSET_TABLE_’ {*UND* section} ..."
gcc3.4.x bug, 编译生成 initfini.s时假如采用了-O2参数,则编译结果不正确
@@@csu/Makefile@@@
  CFLAGS-initfini.s = -g0 -fPIC -fno-inline-functions
+    -fno-unit-at-a-time
@@@linuxthreads/Makefile@@@
linuxthreads/Makefile:
  CFLAGS-pt-initfini.s = -g0 -fPIC -fno-inline-functions
+    -fno-unit-at-a-time

*** "sigaction.c:100: error: asm-specifier for variable `_a1’ conflicts with asm clobber lists"
glibc for arm bug
@@@sysdeps/unix/sysv/linux/arm/sysdep.h@@@
  asm volatile ("swi      %1      @ syscall " #name       \
        : "=r" (_a1)                               \
        : "i" (SYS_ify(name)) ASM_ARGS_##nr        \
-              : "a1", "memory");                         \
+              : "memory");                               \
  _sys_result = _a1;                                      \
       }                                                         \
       (int) _sys_result; })
**** sscanf.c:31: warning: conflicting types for built-in function ’sscanf’

glibc bug,
@@@stdio-common/sscanf.c@@@
  int
- sscanf(s,format)
- const char *s;
- const char *format;
+ sscanf(const char *s,const char *format,...)
  {
**** : Assembler messages:> :2: Error: garbage following instruction -- >
`ldr lr,[sp],#4 ldr ip,=__libc_multiple_threads’
编译linuxthreads出现此问题,原因是宏定义不正确
@@@linuxthreads/sysdeps/unix/sysv/linux/arm/sysdep-cancel.h@@@
  # define PSEUDO(name, syscall_name, args)   \
  .section ".text";     \
  PSEUDO_PROLOGUE;     \
- ENTRY (name)      \
+ ENTRY (name);      \
  SINGLE_THREAD_P_INT;     \
  bne .Lpseudo_cancel;     \
  DO_CALL (syscall_name, args);  
**** ld:/home/jeff/bglibc/libc.so.lds:114: syntax error
libc.so.lds:
  (114) KEEP (*crtbegin.o(.dtors))
  KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
  /usr/local/lib/gcc-lib/i386-linux/3.2.2/libgcc.a(unwind-dw2-fde-glibc.o):  In
  function `size_of_encoded_value’:/home/jeff/gcc-3.2.2/gcc/unwind-pe.h:76:
  undefined reference to `abort’

生成libc.so.lds时,编译的警告信息破坏了libc.so.lds的格式。在确认警告无须理会后,修改Makerules吃掉警告:
@@@Makerules:
$(build-shlib-helper) \
          -o
[email=$@.new]$@.new[/email]
$(csu-objpfx)abi-note.o -Wl,--verbose \
          $(LDLIBS-$(@F:lib%.so=%).so) 2>&1 | \
           sed -e ’/^=========/,/^=========/!d;/^=========/d’ \
+         -es/.*undefined\ reference.*// -es/\\/.*In\ function.*// \
        -e ’s/^.*\.hash[  ]*:.*$$/  .note.ABI-tag : {
*(.note.ABI-tag) } &/’ \
        $(LDSEDCMD-$(@F:lib%.so=%).so) >
[email=$@.lds]$@.lds[/email]
  rm -f
[email=$@.new]$@.new[/email]
**** libc.so.6: undefined reference to `mcount_internal’

glibc在arm上的bug,mcount_internal被定义为static函数
@@@glibc-2.3.2/sysdeps/arm/machine-gmon.h@@@
  weak_alias (_mcount, mcount)
  #endif
  
-static void mcount_internal (u_long frompc, u_long selfpc);

#define _MCOUNT_DECL(frompc, selfpc) \
-static void mcount_internal (u_long frompc, u_long selfpc)
+void mcount_internal (u_long frompc, u_long selfpc)
5 GCC   Shared & g++
在glibc建立好之后,利用glibc重新编译gcc,补充之前限制的特性,并编译g++。应确认toolchain已能够正常编译普通c程式后,才开始进行重编译
配置
  mkdir gccobj.full
  cd gccobj.full
  ../gcc-3.4.3/configure --target=arm-linux --prefix=/usr/armtools --with-sysroot=/usr/armtools/arm-linux/target-root --with-local-prefix=/usr/armtools/arm-linux/target-root --disable-nls --enable-threads=posix --enable-lanuages="c,c++" --enable-c99 --enable-long-long
  make
  make install

 类似资料: