gccの-rdynamic option 調査メモ
はじめに
gccの-rdynamic
optionの調査メモ。
gcc 9.1.0, glibc 2.29を対象に調査した。
基本内容に差はないと思うが、target archはx86_64-pc-linux-gnu。
TL;DR
-
-rdynamic
オプションはリンク時のみ効果がある。
-
-rdynamic
オプションを適用すると、共有ライブラリから実行ファイルのシンボル情報を動的に取得できるので、バックトレースの表示などに使われる。
-
-rdynamic
オプションを適用することで、共有ライブラリとして利用可能な実行ファイルを作成できる。
-
-rdynamic
オプションを適用するとシンボルバッティングや意図せず共有ライブラリに制御されてしまうリスクが増えるので、明確に目的がないなら通常は無効にしておく。
- gcc,glibcのソースコードは面白い。
- gccのspecファイルむずい。
公式ドキュメント
-rdynamic
オプションはリンク時のみ効果がある。-rdynamic
オプションを適用すると、共有ライブラリから実行ファイルのシンボル情報を動的に取得できるので、バックトレースの表示などに使われる。-rdynamic
オプションを適用することで、共有ライブラリとして利用可能な実行ファイルを作成できる。-rdynamic
オプションを適用するとシンボルバッティングや意図せず共有ライブラリに制御されてしまうリスクが増えるので、明確に目的がないなら通常は無効にしておく。GCCには大量の起動オプションがあり、manだと少し見づらい。
そんなときは公式ドキュメントのOption Indexで確認すると楽。
-rdynamic
Pass the flag -export-dynamic to the ELF linker, on targets that support it. This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table. This option is needed for some uses of dlopen or to allow obtaining backtraces from within a program.
曰く、-rdynamic
optionは、Link Options。
すなわち、オブジェクトファイルから実行ファイルを生成するときにのみ作用し、リンクステップがない場合無視される。
そして、-rdynamic
オプションがgcc
に渡された場合、リンカに-export-dynamic
オプションを渡す。
その結果、実行ファイルのすべてのシンボルが.dynsym
テーブルに定義される。
つまり、dlopenなどの動的リンク参照の対象とすることができる。
man ld(1)
の-export-dynamic
オプションの項にも、同等の説明がなされている。
ソースコード調査
gccでは、コマンドラインオプションのパーサ用テーブルは.opt
というオプション定義ファイルからawkで自動生成される。
今回の-rdynamic
optionは下記のように定義されている。
rdynamic
Driver
ちなみに、今回のようにtarget=aarch64-linuxでビルドした場合は、主に下記のoption定義ファイルが使われる。
「主に」としたのは、正確には特定言語用のoption定義ファイルも使われるから。
どのファイルが使われるかは、build-gcc-9.1.0/gcc/config.log
のext_opt_files
, lang_opt_files
で確認可能。
- gcc-9.1.0/gcc/common.opt
- gcc-9.1.0/gcc/c-family/c.opt
- gcc-9.1.0/gcc/config/fused-madd.opt
- gcc-9.1.0/gcc/config/i386/i386.opt
- gcc-9.1.0/gcc/config/gnu-user.opt
- gcc-9.1.0/gcc/config/linux.opt
- gcc-9.1.0/gcc/config/linux-android.opt
これら複数のoption定義ファイルがマージされた結果は、build-gcc-9.1.0/gcc/optionlist
に生成される。
さて、Driverとは何か、gccのinternal documentによれば、
Driver
The option is handled by the compiler driver using code not shared with the compilers proper (cc1 etc.).
すなわち、コンパイラ自体には渡されず、コンパイラドライバだけが使うオプションであることがわかる。
optionlist
から自動生成されたオプションパーサ用テーブルはbuild-gcc-9.1.0/gcc/options.c
に生成される。
cl_options配列に確かに"-rdynamic"に対応するエントリが追加されている。
option定義ファイルに記載されたDriver
に対応するのはCL_DRIVER
。
これはstruct cl_option
のflags
に対応する。
const struct cl_option cl_options[] =
{
...
/* [1491] = */ {
"-rdynamic",
NULL,
NULL,
NULL,
NULL, NULL, N_OPTS, N_OPTS, 8, /* .neg_idx = */ -1,
CL_DRIVER,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
(unsigned short) -1, 0, CLVC_BOOLEAN, 0, -1, -1 },
...
};
struct cl_option
{
...
/* CL_* flags for this option. */
unsigned int flags;
...
};
さらにDRIVERに渡されたオプションは、specsファイルの記述に従って変換されlinkerに渡る。
...
*link:
%{!static|static-pie:--eh-frame-hdr} %{!mandroid|tno-android-ld:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} %{shared:-shared} %{!shared: %{!static: %{!static-pie: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:%{mmusl:/lib/ld-musl-i386.so.1;:/lib/ld-linux.so.2}}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:%{mmusl:/lib/ld-musl-x86_64.so.1;:/lib64/ld-linux-x86-64.so.2}}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:%{mmusl:/lib/ld-musl-x32.so.1;:/libx32/ld-linux-x32.so.2}}}}}} %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}};:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} %{shared:-shared} %{!shared: %{!static: %{!static-pie: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:%{mmusl:/lib/ld-musl-i386.so.1;:/lib/ld-linux.so.2}}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:%{mmusl:/lib/ld-musl-x86_64.so.1;:/lib64/ld-linux-x86-64.so.2}}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:%{mmusl:/lib/ld-musl-x32.so.1;:/libx32/ld-linux-x32.so.2}}}}}} %{static:-static} %{static-pie:-static -pie --no-dynamic-linker -z text}} %{shared: -Bsymbolic}}
...
いろいろ条件はあるようだが、specのドキュメントによれば、
%{rdynamic:-export-dynamic}
で-rdynamic
指定時に-export-dynamic
を指定するらしい。
%{S:X}
Substitutes X, if the -S switch is given to GCC.
実験
.dynsym
セクションの変化を確認
.dynsym
セクションの変化を確認下記の非常にシンプルなプログラムに対し、-rdynamic
オプションの有無で生成されるバイナリの差分を確認した。
#include <stdio.h>
int
func (void)
{
printf ("Hello World\n");
return 0;
}
int
main (void)
{
func ();
return 0;
}
-rdynamic
なし
まずはコンパイル時、リンク時ともに-rdynamic
をつけない場合。
$ gcc -o test.o test.c -c
$ gcc -o test test.o
$ readelf --dyn-sym test
Symbol table '.dynsym' contains 3 entries:
番号: 値 サイズ タイプ Bind Vis 索引名
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
.dynsym
セクションには、スタートアップルーチンから呼び出される__libc_start_main
への参照と、gprof用の__gmon_start__
しかない。
コンパイル時のみ-rdynamic
次にコンパイル時のみ-rdynamic
を有効にした。
想定としては、無視されて何も変わらないはず。
$ gcc -o test.o test.c -c -rdynamic
$ gcc -o test test.o
$ readelf --dyn-sym test
Symbol table '.dynsym' contains 3 entries:
番号: 値 サイズ タイプ Bind Vis 索引名
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
実際、.dynsym
セクションに定義されるシンボルに変更はない。
実行ファイル全体としても-rdynamic
なしの場合とバイナリレベルで一致した。
リンク時のみ-rdynamic
いよいよ、リンク時に-rdynamic
を有効にしてみる。
想定としては、正しく-rdynamic
が作用しfunc()
関数とmain()
関数がdynamic symbolとして見えるはず。
$ gcc -o test.o test.c -c
$ gcc -o test test.o -rdynamic
$ readelf --dyn-sym test
Symbol table '.dynsym' contains 17 entries:
番号: 値 サイズ タイプ Bind Vis 索引名
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND puts@GLIBC_2.2.5 (2)
2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (2)
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
4: 0000000000404038 0 NOTYPE GLOBAL DEFAULT 24 _edata
5: 0000000000404028 0 NOTYPE GLOBAL DEFAULT 24 __data_start
6: 0000000000404040 0 NOTYPE GLOBAL DEFAULT 25 _end
7: 0000000000404028 0 NOTYPE WEAK DEFAULT 24 data_start
8: 0000000000402000 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
9: 0000000000401160 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
10: 0000000000401060 42 FUNC GLOBAL DEFAULT 14 _start
11: 0000000000404038 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
12: 0000000000401147 16 FUNC GLOBAL DEFAULT 14 main
13: 0000000000401000 0 FUNC GLOBAL DEFAULT 11 _init
14: 0000000000401132 21 FUNC GLOBAL DEFAULT 14 func
15: 00000000004011d0 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
16: 00000000004011d4 0 FUNC GLOBAL DEFAULT 15 _fini
実際、.dynsym
セクションにfunc()
関数とmain()
関数が追加されている。
さらに、関数だけでなくリンカが作成した__bss_start
などのシンボルも.dynsym
セクションにエントリがある。
コンパイル・リンク同時実行時に-rdynamic
一応コンパイルとリンクを同時に実行する場合に-rdynamic
をつけた場合も確認した。
$ gcc -o test test.c -c -rdynamic
$ readelf --dyn-sym test
(同じなので略)
予想通り、リンク時と同じ結果が得られた(実行ファイルバイナリ一致)。
dlopenによるシンボル取得
次に、下記のようなdlopen()
を使った簡単なプログラムで、実際に実行ファイル中のシンボルを参照してみる。
なお、dlopen()
の第一引数をNULLにすることで、実行ファイル自体を指定することができる。
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <dlfcn.h>
extern const char *__bss_start[];
uint32_t
func (void)
{
return 0xdeadbeef;
}
int
main (void)
{
char *error = NULL;
void *handle = dlopen (NULL, RTLD_LAZY);
if (!handle)
{
fprintf (stderr, "%s\n", dlerror());
exit (EXIT_FAILURE);
}
dlerror (); /* Clear any existing error */
int (*dyn_func)(void) = (int (*)(void)) dlsym (handle, "func");
error = dlerror ();
if (error != NULL)
{
fprintf (stderr, "%s\n", error);
exit (EXIT_FAILURE);
}
Dl_info info_func;
int result = dladdr (dyn_func, &info_func);
if (result == 0)
{
fprintf (stderr, "dladdr error for dyn_func %d\n", result);
exit (EXIT_FAILURE);
}
void* dyn_bss_start = (void*) dlsym (handle, "__bss_start");
error = dlerror ();
if (error != NULL)
{
fprintf (stderr, "%s\n", error);
exit (EXIT_FAILURE);
}
Dl_info info_bss_start;
result = dladdr (dyn_bss_start, &info_bss_start);
if (result == 0)
{
fprintf (stderr, "dladdr error for dyn_bss_start %d\n", result);
exit (EXIT_FAILURE);
}
dlclose (handle);
uint32_t ret = func();
printf ("func(direct) = %p, ret = 0x%x\n", func, ret);
ret = dyn_func();
printf ("func(dlopen) = %p, ret = 0x%x\n", dyn_func, ret);
printf ("dladdr(func)\n"
" .dli_fname = \"%s\", .dlt_fbase = %p,\n"
" .dli_sname = \"%s\", .dli_saddr = %p\n",
info_func.dli_fname, info_func.dli_fbase,
info_func.dli_sname, info_func.dli_saddr);
printf ("__bss_start(direct) = %p\n", __bss_start);
printf ("__bss_start(dlopen) = %p\n", dyn_bss_start);
printf ("dladdr(__bss_start)\n"
" .dli_fname = \"%s\", .dlt_fbase = %p,\n"
" .dli_sname = \"%s\", .dli_saddr = %p\n",
info_bss_start.dli_fname, info_bss_start.dli_fbase,
info_bss_start.dli_sname, info_bss_start.dli_saddr);
return 0;
}
-rdynamic
なし
とりあえず-rdynamic
オプションなしで実行。
予想通り、dlopen()
は成功して、dlsym()
で"test"が見つけられず失敗した。
$ gcc -o test_dlopen test_dlopen.c -ldl
$ ./test_dlopen
./test-no-rdynamic: undefined symbol: test
-rdynamic
あり
次に、-rdynamic
オプションありで実行。
test関数、__bss_startシンボルともに見つけることができている。
さらにそれぞれのアドレスは、直接参照した場合と同じとなっており、当然だが関数呼び出しもできている。
dladdr()
で取得した.dli_fname
(ファイル名)は正しく"./test"を返している。
一方、.dli_sname
(symbol名)は、func
関数については正しく"func"となっているが、
__bss_start
については、"edata"となっている。
これは、readelf --dyn-sym
の結果を見ればわかるが、同じアドレスで_edata
と`_bss_start`という異なるシンボルを持っているため発生したと思われる。
実際、自分で適当にグローバル変数を定義し、参照した場合はこのようなことは発生しなかった。
$ gcc -o test_dlopen test_dlopen.c -ldl -rdynamic
$ ./test
func(direct) = 0x4011a2, ret = 0xdeadbeef
func(dlopen) = 0x4011a2, ret = 0xdeadbeef
dladdr(func)
.dli_fname = "./test", .dlt_fbase = 0x400000,
.dli_sname = "func", .dli_saddr = 0x4011a2
__bss_start(direct) = 0x404070
__bss_start(dlopen) = 0x404070
dladdr(__bss_start)
.dli_fname = "./test", .dlt_fbase = 0x400000,
.dli_sname = "_edata", .dli_saddr = 0x404070
$ readelf --dyn-sym test | grep 404070
11: 0000000000404070 0 NOTYPE GLOBAL DEFAULT 24 _edata
18: 0000000000404070 0 NOTYPE GLOBAL DEFAULT 25 __bss_start
いつ使うのか
さて、なかなかに好奇心をくすぐってくれる-rdynamic
オプションだが、実際どのようなときに使われるのか。
調べた限りでは、下記2種類の用途が見つかった。
他にもあればぜひ教えてください。
backtrace取得
デバッグ機能を提供するライブラリから実行ファイルの情報を取得するとき、シンボルテーブルを動的に参照したい、というのはとてもわかり易い。
実際、glibcが提供するbacktrace_symbols()
では、manにて下記のように-rdynamic
に言及されている。
バックトレース情報をアドレス値として表示する分には不要だが、一緒に関数名を表示するためには-rdynamic
オプションが必要。
The symbol names may be unavailable without the use of special linker options. For systems using the GNU linker, it is necessary to
use the -rdynamic linker option. Note that names of "static" functions are not exposed, and won't be available in the backtrace.
backtrace_symbols
のコードを見ればdladdr
を使っているからということがわかる。
char **
__backtrace_symbols (void *const *array, int size)
{
Dl_info info[size];
...
/* Fill in the information we can get from `dladdr'. */
for (cnt = 0; cnt < size; ++cnt)
{
struct link_map *map;
status[cnt] = _dl_addr (array[cnt], &info[cnt], &map, NULL);
if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')
{
/* We have some info, compute the length of the string which will be
"<file-name>(<sym-name>+offset) [address]. */
total += (strlen (info[cnt].dli_fname ?: "")
+ strlen (info[cnt].dli_sname ?: "")
+ 3 + WORD_WIDTH + 3 + WORD_WIDTH + 5);
/* The load bias is more useful to the user than the load
address. The use of these addresses is to calculate an
address in the ELF file, so its prelinked bias is not
something we want to subtract out. */
info[cnt].dli_fbase = (void *) map->l_addr;
}
else
total += 5 + WORD_WIDTH;
}
...
なお、libSegFault.soは内部でbacktrace_symbols_fd(3)
を使用しているので同類。
/* This function is called when a segmentation fault is caught. The system
is in an unstable state now. This means especially that malloc() might
not work anymore. */
static void
catch_segfault (int signal, SIGCONTEXT ctx)
{
...
/* Get the backtrace. */
arr = alloca (256 * sizeof (void *));
cnt = backtrace (arr, 256);
...
/* Now generate nicely formatted output. */
__backtrace_symbols_fd (arr + i, cnt - i, fd);
ちなみに実は、gcc自身もpluginをサポートする環境では、-rdynamic
オプションありでビルドされる。
なぜpluginだと-rdynamic
が必要なのか。
もちろんpluginのシンボルを取り出すためにdlopen
等が必要にはなるが、
それは本来の向きのdlopen
であって、実行ファイル側のdynamic symbol tableは関係ないはずだ。
正確な答えは不明だが、こちらの記事のようにpluginを開発している人が、
backtraceを使って効率よく開発できるようにするための措置ではないかと思う。
逆にいえば、gcc自身ですら必要とされるとき以外は無効にしているので、
明確な目的がない場合は-rdynamic
オプションは無効にしておくのが良いといえるだろう。
実行可能な共有ライブラリを作成するとき
共有ライブラリでありつつ、単体で実行も可能だと便利な時がある。
バージョンや、どのようなオプションでビルドされたかの情報を表示するときだ。
バイナリ配布されるライブラリは、パッケージマネージャやheader、pkg-configなどにバージョンを書くことができるが、
いずれもライブラリそのものとは別ファイルでバージョンを管理することになるので、
いつの間にかバージョン情報とバイナリが乖離してしまう可能性がある。
ライブラリそのものがバージョンを語ることができれば、それが一番間違いがない。
$ lib/libc.so.6
GNU C Library (GNU libc) stable release version 2.29.
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 9.1.0.
libc ABIs: UNIQUE IFUNC ABSOLUTE
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
このような実行可能共有ライブラリを作るためには、
下記のようにビルドすればいい。
-
-fPIC
でコンパイル -
-shared -pie -rdynamic
でリンク
共有ライブラリのソースコード。
#include <stdio.h>
#include <stdlib.h>
int
func (int a, int b)
{
return a + b;
}
int
main (void)
{
printf ("This is executable solib (%s)\n", __func__);
exit (EXIT_SUCCESS);
}
共有ライブラリを使うソースコード。
#include <stdio.h>
#include <assert.h>
extern int func (int a, int b);
int
main (void)
{
assert (func (2, 3) == 5);
printf ("test passed\n");
return 0;
}
単体としても実行できているし、共有ライブラリとしても使えている。
$ gcc -g -o executable_solib.o executable_solib.c -c -fPIC
$ gcc -o libexecutable.so executable_solib.o -shared -pie -rdynamic
$ gcc -g -o test_executable_solib.o test_executable_solib.c -c
$ gcc -g -o test_executable_solib test_executable_solib.o -L. -Wl,-rpath=. -lexecutable
$ ./libexecutable.so
This is executable solib
$ ./test_executable_solib
test passed
さて、ではglibcのリンクオプションを確認してみる。
下記は実際にglibc-2.29をビルドした時のリンクコマンドだ。
gcc
-shared
-static-libgcc
-Wl,-O1
-Wl,-z,defs
-Wl,-dynamic-linker=/work/install/lib/ld-linux-x86-64.so.2
-B/work/build-glibc-2.29/csu/
-Wl,--version-script=/work/build-glibc-2.29/libc.map
-Wl,-soname=libc.so.6
-Wl,-z,combreloc
-Wl,-z,relro
-Wl,--hash-style=both
-nostdlib
-nostartfiles
-e __libc_main
-L/work/build-glibc-2.29
-L/work/build-glibc-2.29/math
-L/work/build-glibc-2.29/elf
-L/work/build-glibc-2.29/dlfcn
-L/work/build-glibc-2.29/nss
-L/work/build-glibc-2.29/nis
-L/work/build-glibc-2.29/rt
-L/work/build-glibc-2.29/resolv
-L/work/build-glibc-2.29/mathvec
-L/work/build-glibc-2.29/support
-L/work/build-glibc-2.29/crypt
-L/work/build-glibc-2.29/nptl
-Wl,-rpath-link=/work/build-glibc-2.29
:/work/build-glibc-2.29/math
:/work/build-glibc-2.29/elf
:/work/build-glibc-2.29/dlfcn
:/work/build-glibc-2.29/nss
:/work/build-glibc-2.29/nis
:/work/build-glibc-2.29/rt
:/work/build-glibc-2.29/resolv
:/work/build-glibc-2.29/mathvec
:/work/build-glibc-2.29/support
:/work/build-glibc-2.29/crypt
:/work/build-glibc-2.29/nptl
-o /work/build-glibc-2.29/libc.so
-T /work/build-glibc-2.29/shlib.lds
/work/build-glibc-2.29/csu/abi-note.o
/work/build-glibc-2.29/elf/soinit.os
/work/build-glibc-2.29/libc_pic.os
/work/build-glibc-2.29/elf/interp.os
/work/build-glibc-2.29/elf/ld.so
-lgcc
/work/build-glibc-2.29/elf/sofini.os
-rdynamic
がない。。。
同等の効果をもつ、-Wl,-E
, -Wl,--export-dynamic
もない。。。
-pie
もない。。。
ということで、残念ながらglibcは別の方法で実現していた。
がせっかくなので、実現方法を確認してみる。
まずはエントリポイントを-e
オプションで__libc_main
変更しているので、そこから確認してみる。
void
__libc_main (void)
{
__libc_print_version ();
_exit (0);
}
versionを出力して終了しているだけ。
では、__libc_print_version
は?
void
__libc_print_version (void)
{
__write (STDOUT_FILENO, banner, sizeof banner - 1);
}
おぉ、直接システムコールを呼び出してバージョンを出力しているのか。
これを見て気づいたが、glibcの場合文字列を出力するだけなら外部ライブラリを参照することがない。
そのため位置独立な実行ファイルにする必要がなくて-pie
をつけなくていい。
-pie
をつけなければリンカは-shared
が指定されているからdynamic symbolをすべて公開するので、-rdynamic
もいらない、と。
前述の-rdynamic
オプションを使った方法は、「動的リンク可能な実行ファイル」、
glibcはあくまでも「entryポイントが設定された共有ライブラリ」、ということか。
おまけ(ビルド手順)
今回の実験で使ったaarch64-linux向けのクロスコンパイラのビルド手順は下記の通り。
x84-64向け
# インストール先ディレクトリ
mkdir -p install
# binutils-2.32 (as, ld等)のビルド
wget https://ftp.gnu.org/gnu/binutils/binutils-2.32.tar.xz
tar xf binutils-2.32.tar.xz
mkdir -p build-binutils-2.32
cd build-binutils-2.32
../binutils-2.32/configure --prefix=${PWD}/../install
make -j12
make install
cd ..
# gcc-9.1.0のビルド
wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.xz
tar xf gcc-9.1.0.tar.xz
mkdir -p build-gcc-9.1.0
cd build-gcc-9.1.0
../gcc-9.1.0/configure --prefix=${PWD}/../install --enable-languages=c,c++ --disable-multilib
make -j12 all-gcc
make install-gcc
make -j12 all-target-libgcc
make install-target-libgcc
cd ..
# glibcのビルド
wget http://ftp.jaist.ac.jp/pub/GNU/glibc/glibc-2.29.tar.xz
tar xf glibc-2.29.tar.xz
mkdir -p build-glibc-2.29
cd build-glibc-2.29
../gcc-9.1.0/configure --prefix=${PWD}/../install
make -j12
make install
cd ..
# ちゃんとビルドできたか確認
export PATH="${PWD}/install/bin/:$PATH"
as --version # 2.32のはず
ld --version # 2.32のはず
gcc --version # 9.10のはず
aarch64-linux向け
下記でld/gccのビルドはできるが、それらで実際にリンクまでするためには、さらにkernel headerやlibcの準備が必要なので注意。
# インストール先ディレクトリ
mkdir -p install
# binutils-2.32 (as, ld等)のビルド
wget https://ftp.gnu.org/gnu/binutils/binutils-2.32.tar.xz
tar xf binutils-2.32.tar.xz
mkdir -p build-binutils-2.32
cd build-binutils-2.32
../binutils-2.32/configure --prefix=${PWD}/../install --target=aarch64-linux
make -j12
make install
cd ..
# gcc-9.1.0のビルド
wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-9.1.0/gcc-9.1.0.tar.xz
tar xf gcc-9.1.0.tar.xz
mkdir -p build-gcc-9.1.0
cd build-gcc-9.1.0
../gcc-9.1.0/configure --prefix=${PWD}/../install --target=aarch64-linux --enable-languages=c,c++ --disable-multilib
make -j12 all-gcc
make install-gcc
cd ..
# ちゃんとビルドできたか確認
export PATH="${PWD}/install/bin/:$PATH"
aarch64-linux-as --version # 2.32のはず
aarch64-linux-ld --version # 2.32のはず
aarch64-linux-gcc --version # 9.10のはず
参考ページ
- GCC Online Documentation (9.1.0)
- GCC Option Index
- GCC Internal Documentation
- Option Specification Files
- How to Build a GCC Cross-Compiler
- 最低限のクロスコンパイラの作り方
- glibc Backtraces
- [Linux][C/C++] backtrace取得方法まとめ
- 単体でも実行可能で動的リンクも可能な共有ライブラリを作成する
- Why and how are some shared libraries runnable, as though they are executables?
- GCC pluginを試してみる
Author And Source
この問題について(gccの-rdynamic option 調査メモ), 我々は、より多くの情報をここで見つけました https://qiita.com/takeoverjp/items/14fdf7ab0d0a76d83d30著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .