GCC Spec

Table of Contents

1. GCC Spec

1.1. overview

https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html

gcc 是一个 driver 程序, 它负责调用 cc1/as/ld 等程序. spec 解决的主要问题是调用 cc1/as/ld 时如何控制它们的参数. 通过修改 spec 文件, 我们可以:

  1. 修改 cc1/as/ld 的参数
  2. 给 gcc driver 添加参数, 并映射成 cc1/as/ld 的参数

gcc 默认的 spec 是在 `gcc/gcc.cc` 中指定后编译到 gcc 中的, 后端可通过 `#define CC1_SPEC xxx` 的形式修改 spec.

通过 `gcc -dumpspecs` 可以得到默认的 spec, 通过 `–specs=xxx.spec` 可以指定新的 spec

1.2. 基本格式

以 gcc 调用 linker 时的参数为例:

*linker:
collect2

*link_gcc_c_sequences:
%G %{!nolibc:%(lib) %G} -lgcc
// %G 即 %(libgcc), 通过 %(libgcc) 可以把 `*libgcc` include 到这里, 即给 ld 加上 `-lgcc` 参数
// %{!nolibc:%(lib)} 是指如果 gcc 没有指定 `-nolibc`, 则通过 include `*lib` 把 `-lc` 等参数传递给 ld


*lib:
--start-group -lc %{!specs=nosys.specs:-lgloss} --end-group

*libgcc:
-lgcc

*startfile:
crt0%O%s crtbegin%O%s

*endfile:
crtend.o%s

*link_command:
%(linker)
...
%{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequences)}}
%{!nostdlib:%{!nostartfiles:%S}}
%{!nostdlib:%{!nostartfiles:%E}}
...
// include `*linker`, 即调用 collect2 做为 linker
// 如果没有指定 nostdlib 和 nodefaultlibs, 则 include `*link_gcc_c_sequences`
// 如果没有指定 nostdlib 和 nostartfiles, 则 include `*startfile` 和 `*endfile`

所以 spec 主要元素是:

  • `*xxx`

    定义 spec, 用来指示某个程序 (as/cc1/ld) 使用的参数, gcc 预定义了几个 `*xxx`, 例如: `*asm`, `*cc1_options`, `*link`, 其中 `*asm` 表示调用 as 时使用的参数.

    用户也可以自定义 spec, 然后通过 `%(xxx) 的形式 include 到其它 spec

  • `%(xxx)
  • `%{a:b}` 表示 gcc 的 `-a` 参数映射为当前 spec 对应的程序 (as/cc1/ld) 的 `b` 参数

1.3. 通过 spec 添加参数

例如, 通过 spec 给 gcc 添加一个 `–foo` 参数, 并且把这个参数映射为 as 的 `-foox` 以及 cc1 的 `-fooy` 参数:

*asm:
... %{-foo:-foox}

*cc1_options:
... %{-foo:-fooy}

由于默认的 cc1_options 中包含 `%{m*} %{f*}`, 所以 gcc 的 `-mxxx`, `-fxxx` 总是会原封不动的传递给 cc1. 添加这种名字的 gcc 参数需要注意

1.4. 通过 spec 修改参数

nano.specs 是使用 nano libc 的 spec. nano.specs 主要是修改了默认 spec 需要用到的 `*link_gcc_c_sequence`, `*link`, `*cpp` 等 spec, 把相应参数替换为 nano 的版本, 特别的, 它通过 `replace-outfile` 把原来的 `-lc` 替换成为 `-lc_nano`

%rename link                nano_link
%rename link_gcc_c_sequence                nano_link_gcc_c_sequence
%rename cpp             nano_cpp

*cpp:
-isystem =/include/newlib-nano %(nano_cpp)

*nano_libc:
-lc_nano

*nano_libgloss:
%{specs=nosys.specs:-lnosys} %{!specs=nosys.specs:-lgloss_nano}

*link_gcc_c_sequence:
%(nano_link_gcc_c_sequence) --start-group %G %(nano_libc) %(nano_libgloss) --end-group

*link:
%(nano_link) %:replace-outfile(-lc -lc_nano) %:replace-outfile(-lg -lg_nano) %:replace-outfile(-lm -lm_nano)

*lib:
%{!shared:%{g*:-lg_nano} %{!p:%{!pg:-lc_nano}}%{p:-lc_p}%{pg:-lc_p}}

gcc 可以指定多个 spec, 且后面定义的 spec 中的 `*xxx` 会覆盖前面的, 通过 `%rename` 可以保留旧的 spec, 从而实现修改而不是覆盖.

Backlinks

Bare Metal (Bare Metal > 实现): baremetal 与 linux 工具链的区别主要体现在 spec 中, spec 的定义和处理是在 `gcc.cc`, 它会使用 config.gcc 中定义的头文件:

GCC Multilib (GCC Multilib > gcc > 运行时查找 multilib dir): 以上 makefile 中定义的的 MULTILIB_XXX 做为运行时参数会通过 spec 保存在 gcc 中, gcc 在运行时查找 startfile(通过 find_file)或构造 library path (-L xxx) 时, 会处 理这些 spec:

Author: [email protected]
Date: 2023-09-19 Tue 10:40
Last updated: 2024-01-09 Tue 13:53

知识共享许可协议