标题: 在x86上交叉编译ARM版gdb的注意事项 创建: 2018-09-28 17:53 更新: 2019-01-16 14:30 链接: https://scz.617.cn/unix/201809281753.txt 假设当前开发环境是x86/Debian,目标系统是一个3.0.x内核的ARM版Linux,后者用 的是uClibc。现在希望编译出静态链接的ARM版gdb、gdbserver。 有人说只要ARM版gdbserver即可,多弄一个ARM版gdb自有我的道理。有人说,gdb应 该是x86版的,只不过configure时target指定成ARM,我知道这种意图所在,但那不 是本文关注点,我不打算在x86版gdb中"target remote ..."。事实上我有与ARM版 gdbserver相配合的x86工具IDA,我也有另一个ARM/Debian跑原生gdb。不再废话。 常见的两种交叉编译工具: arm-none-eabi-gcc arm-none-linux-gnueabi-gcc 前者一般用于编译单片机固件,osmocom-bb项目、EZ-Connect Lite SDK等等用的是 前者。后者是全功能的,头文件带得整齐。如果target是Linux而非单片机,必须用 后者。 交叉编译工具链一般不是OS原生自带的。绝大多数人不需要自己下载gcc源码并编译 生成相应的交叉编译工具链,我也只干过一次,折腾osmocom-bb项目时,自己编译生 成arm-none-eabi-gcc 4.8.2。一般来说,放狗,下载别人提供的二进制包,这种包 无所谓安装,解压后放在任何路径,使用前用"export PATH=$PATH:"设置一下 环境变量,确保arm-...-gcc在PATH中即可。可以说交叉编译工具链是一种100%纯绿 色软件。我在x86/Debian上装了很多套不同的交叉编译工具链,不修改/etc/profile 之类的,需要用哪个了就在当前shell里临时设一下PATH。 回到原始目标,看看我干过的变态事情: 用arm-xxx-linux-gcc交叉编译ncurses-5.9 用arm-xxx-linux-gcc交叉编译gdb-7.5 用arm-linux-gnueabi-gcc 8.2.0交叉编译ncurses-5.9(失败) 用arm-linux-gnueabi-gcc 8.2.0交叉编译ncurses-6.1 用arm-linux-gnueabi-gcc 8.2.0交叉编译gdb-7.5(半成功) 用arm-yyy-linux-gcc交叉编译ncurses-6.1 用arm-yyy-linux-gcc交叉编译gdb-7.5 用arm-yyy-linux-gcc交叉编译gdb-8.2(失败) 用arm-xxx-linux-gcc交叉编译gdb-7.11(失败) 用arm-none-linux-gnueabi-gcc 4.6.1交叉编译ncurses-6.1 用arm-none-linux-gnueabi-gcc 4.6.1交叉编译gdb-8.2(失败) 用arm-none-eabi-gcc 4.8.2交叉编译ncurses-6.1(失败) 用arm-none-linux-gnueabi-gcc 4.6.1交叉编译gdb-7.11(有瑕疵) 用arm-yyy-linux-gcc交叉编译gdb-7.11(有瑕疵) 用arm-none-linux-gnueabi-gcc 4.6.1交叉编译gdb-7.12 用arm-none-linux-gnueabi-gcc 4.8.3交叉编译ncurses-6.1 用arm-none-linux-gnueabi-gcc 4.8.3交叉编译gdb-8.2 arm-xxx-linux-gcc、arm-yyy-linux-gcc是目标系统配套的编译工具,尽管目标系统 没有公开告诉我这点,但我还是设法识别出并弄到了它们。一个用uClibc,另一个用 glibc,它们最多只能处理gdb-7.5。 arm-none-linux-gnueabi-gcc 4.6.1可以处理gdb-7.12,无法处理gdb-8.2。 arm-none-linux-gnueabi-gcc 4.8.3幺蛾子最少,可以处理此刻最新的gdb-8.2,不 需要动任何其他手脚就可以顺利编译完成。 arm-...-gcc的版本不能太高。arm-linux-gnueabi-gcc 8.2.0是Debian 9原装货,它 的glibc只能向下兼容到3.2.0版kernel,用它编译出来的静态链接的ARM版gdb在前述 目标系统上运行时会报错: FATAL: kernel too old Aborted 为了交叉编译gdb,必须提前编译、安装ncurses库,5.9、6.1版都可以,能用新的就 用新的。如果target是x86,一般有现成的ncurses库,target是ARM时很可能需要自 己编译、安装ncurses库。 [scz@ /tmp]> arm-none-linux-gnueabi-gcc --version arm-none-linux-gnueabi-gcc (Sourcery CodeBench Lite 2014.05-29) 4.8.3 20140320 (prerelease) [scz@ /tmp]> arm-none-linux-gnueabi-gcc -print-search-dirs 这将显示arm-none-linux-gnueabi-gcc的搜索路径,比如从哪里找库文件,后面会用 到。 http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz [scz@ /tmp]> mkdir ncurses [scz@ /tmp]> cd ncurses [scz@ /tmp/ncurses]> tar xfz /tmp/ncurses-6.1.tar.gz [scz@ /tmp/ncurses/ncurses-6.1]> mkdir build-glibc [scz@ /tmp/ncurses/ncurses-6.1/build-glibc]> ../configure --host=arm-none-linux-gnueabi make [scz@ /tmp/ncurses/ncurses-6.1/build-glibc]> ls -l lib 108608 Sep 28 16:33 libform.a 644854 Sep 28 16:33 libform_g.a 58042 Sep 28 16:33 libmenu.a 358612 Sep 28 16:33 libmenu_g.a 532756 Sep 28 16:33 libncurses.a 3017858 Sep 28 16:33 libncurses_g.a 25056 Sep 28 16:33 libpanel.a 224128 Sep 28 16:33 libpanel_g.a [scz@ /tmp/ncurses/ncurses-6.1/build-glibc]> ls -l include 0 Sep 28 16:32 config.h 81745 Sep 28 16:32 curses.h 69308 Sep 28 16:32 curses.head 2891 Sep 28 16:33 eti.h 18601 Sep 28 16:33 form.h 109 Sep 28 16:32 hashsize.h 6538 Sep 28 16:32 Makefile 12197 Sep 28 16:33 menu.h 3942 Sep 28 16:33 mf_common.h 16696 Sep 28 16:32 MKterm.h.awk 7171 Sep 28 16:32 ncurses_cfg.h 12377 Sep 28 16:32 ncurses_def.h 4277 Sep 28 16:32 ncurses_dll.h 4123 Sep 28 16:33 panel.h 9265 Sep 28 16:32 parametrized.h 3470 Sep 28 16:32 termcap.h 40262 Sep 28 16:32 term.h 3099 Sep 28 16:32 unctrl.h 把lib子目录下的一堆静态库(.a)复制到arm-none-linux-gnueabi-gcc的搜索路径中 去。不需要复制头文件。 [scz@ /tmp/ncurses/ncurses-6.1/build-glibc]> cp lib/lib* 如果之前没有编译安装ncurses库,编译gdb时可能会碰上错误提示: configure: error: no termcap library found http://ftp.gnu.org/gnu/gdb/gdb-8.2.tar.xz [scz@ /tmp]> mkdir gdb [scz@ /tmp]> cd gdb [scz@ /tmp/gdb]> xz -cd /tmp/gdb-8.2.tar.xz | tar xf - [scz@ /tmp/gdb]> cd gdb-8.2 [scz@ /tmp/gdb/gdb-8.2]> mkdir build-glibc [scz@ /tmp/gdb/gdb-8.2]> cd build-glibc [scz@ /tmp/gdb/gdb-8.2/build-glibc]> ../configure --without-python --disable-tui --host=arm-none-linux-gnueabi LDFLAGS="-static" [scz@ /tmp/gdb/gdb-8.2/build-glibc]> make [scz@ /tmp/gdb/gdb-8.2/build-glibc]> arm-none-linux-gnueabi-strip gdb/gdb gdb/gdbserver/gdbserver [scz@ /tmp/gdb/gdb-8.2/build-glibc]> ls -l gdb/gdb gdb/gdbserver/gdbserver 5680440 Sep 28 16:57 gdb/gdb* 1023680 Sep 28 16:57 gdb/gdbserver/gdbserver* [scz@ /tmp/gdb/gdb-8.2/build-glibc]> file -b gdb/gdb gdb/gdbserver/gdbserver ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, stripped ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, for GNU/Linux 2.6.16, stripped 它的glibc向下兼容到2.6.16版kernel,在3.0.x版kernel的target上运行绰绰有余。 我在编译ncurses、gdb时都提前创建了一个名为build-glibc的子目录,然后在其中 configure、make。创建这个子目录不是必须的,只不过洁癖使然,像我这样干,很 容易一删了之,不污染父目录。为此还曾在Solaris上惹过麻烦,有兴趣者参看: 《自编译GDB执行出错后的排查》 https://scz.617.cn/unix/201603011322.txt 编译gdb时我在configure的未尾放了LDFLAGS="-static",可以不放这里,而是放在 make的未尾,即: make LDFLAGS="-static" 这个没有优劣对错,可以理解成vi与emacs、行尾{与行首{、goto与while(1)/break 等等,你懂的。 说个不相关的,经常用tar,没想到这还是个有效单词,沥青、柏油。我第一次在计 算机领域之外看到它,想当然地以为是要打包啥啥。据说*nix程序员们经常用到的命 令还有: $ unzip; strip; touch; grep; finger; mount; fsck; more; yes; umount; sleep 2019-01-15 21:22 Constantinopolis https://github.com/crosstool-ng/crosstool-ng/ http://crosstool-ng.github.io/