4.3.3. 初始化库函数调用表
机器描述文件给出了一个途径把特定的操作构建为RTL形式。对于指令生成,编译器尝试打开已编码的RTL代码(如果是开放编码的(open-coded),没有进行真正的函数调用,只是在同等代码的展开;而封闭编码的(close-coded)则导致函数的调用。在编译器界(compiler circles),短语“开放编码”(open coded)的含义甚至更为宽泛。例如,某些机器具有花哨的指令来完成某些计算中的几步,比如计算多项式的POLY指令,或使用数组下标的INDEX指令(有时带有内建的构建检查)。事实证明,给定架构的在特定实现上,执行多个简单的指令比使用这个花哨指令要快。这在有可选加速硬件的微编码(microcoded)系统中,更容易发生——例如,INDEX可能微编码了一个乘法,需要十多个时钟周期,而更简单的MUL然后ADD使用硬件乘法器,故能在几个时钟周期完成。现今,除了并行分发(parallel-issue)微处理器,通常都会发生:例如,x86的ENTER指令,在某些x86 CPU上,比等效的指令序列更慢。(尤其在因为某些特别的知识,例如,“我们知道在这个叶函数(leaf function)中,不需要分开的栈,栈框指针,也不需要任何栈调整”,编译器可以省略一些步骤的情况下)编译器开发者,在避免了使用慢的ENTER和EXIT指令时,会这样说“ 我们开放编码了函数的进入与退出”)。如果不可能,编译器将调用库例程来处理操作。
lang_dependent_init (continue)
4540 init_optabs ();
5177 void
5178 init_optabs (void) in optabs.c
5179 {
5180 unsigned int i;
5181
5182 /* Start by initializing all tables to contain CODE_FOR_nothing. */
5183
5184 for (i = 0; i < NUM_RTX_CODE; i++)
5185 setcc_gen_code[i] = CODE_FOR_nothing;
5186
5187 #ifdef HAVE_conditional_move
5188 for (i = 0; i < NUM_MACHINE_MODES; i++)
5189 movcc_gen_code[i] = CODE_FOR_nothing;
5190 #endif
由表示条件(比如,EQ,LT等)的rtx-code索引的setcc_gen_code给出了指令码,来构建测试该条件的条件保存指令。而由机器模式索引的movcc_gen_code给出了指令码,来构建一个条件移动指令。
init_optabs (continue)
5192 add_optab = init_optab (PLUS);
5193 addv_optab = init_optabv (PLUS);
5194 sub_optab = init_optab (MINUS);
5195 subv_optab = init_optabv (MINUS);
5196 smul_optab = init_optab (MULT);
5197 smulv_optab = init_optabv (MULT);
5198 smul_highpart_optab = init_optab (UNKNOWN);
5199 umul_highpart_optab = init_optab (UNKNOWN);
5200 smul_widen_optab = init_optab (UNKNOWN);
5201 umul_widen_optab = init_optab (UNKNOWN);
5202 sdiv_optab = init_optab (DIV);
5203 sdivv_optab = init_optabv (DIV);
5204 sdivmod_optab = init_optab (UNKNOWN);
5205 udiv_optab = init_optab (UDIV);
5206 udivmod_optab = init_optab (UNKNOWN);
5207 smod_optab = init_optab (MOD);
5208 umod_optab = init_optab (UMOD);
5209 ftrunc_optab = init_optab (UNKNOWN);
5210 and_optab = init_optab (AND);
5211 ior_optab = init_optab (IOR);
5212 xor_optab = init_optab (XOR);
5213 ashl_optab = init_optab (ASHIFT);
5214 ashr_optab = init_optab (ASHIFTRT);
5215 lshr_optab = init_optab (LSHIFTRT);
5216 rotl_optab = init_optab (ROTATE);
5217 rotr_optab = init_optab (ROTATERT);
5218 smin_optab = init_optab (SMIN);
5219 smax_optab = init_optab (SMAX);
5220 umin_optab = init_optab (UMIN);
5221 umax_optab = init_optab (UMAX);
5222 pow_optab = init_optab (UNKNOWN);
5223 atan2_optab = init_optab (UNKNOWN);
5224
5225 /* These three have codes assigned exclusively for the sake of
5226 have_insn_for. */
5227 mov_optab = init_optab (SET);
5228 movstrict_optab = init_optab (STRICT_LOW_PART);
5229 cmp_optab = init_optab (COMPARE);
5230
5231 ucmp_optab = init_optab (UNKNOWN);
5232 tst_optab = init_optab (UNKNOWN);
5233
5234 eq_optab = init_optab (EQ);
5235 ne_optab = init_optab (NE);
5236 gt_optab = init_optab (GT);
5237 ge_optab = init_optab (GE);
5238 lt_optab = init_optab (LT);
5239 le_optab = init_optab (LE);
5240 unord_optab = init_optab (UNORDERED);
5241
5242 neg_optab = init_optab (NEG);
5243 negv_optab = init_optabv (NEG);
5244 abs_optab = init_optab (ABS);
5245 absv_optab = init_optabv (ABS);
5246 addcc_optab = init_optab (UNKNOWN);
5247 one_cmpl_optab = init_optab (NOT);
5248 ffs_optab = init_optab (FFS);
5249 clz_optab = init_optab (CLZ);
5250 ctz_optab = init_optab (CTZ);
5251 popcount_optab = init_optab (POPCOUNT);
5252 parity_optab = init_optab (PARITY);
5253 sqrt_optab = init_optab (SQRT);
5254 floor_optab = init_optab (UNKNOWN);
5255 ceil_optab = init_optab (UNKNOWN);
5256 round_optab = init_optab (UNKNOWN);
5257 btrunc_optab = init_optab (UNKNOWN);
5258 nearbyint_optab = init_optab (UNKNOWN);
5259 sin_optab = init_optab (UNKNOWN);
5260 cos_optab = init_optab (UNKNOWN);
5261 exp_optab = init_optab (UNKNOWN);
5262 log_optab = init_optab (UNKNOWN);
5263 tan_optab = init_optab (UNKNOWN);
5264 atan_optab = init_optab (UNKNOWN);
5265 strlen_optab = init_optab (UNKNOWN);
5266 cbranch_optab = init_optab (UNKNOWN);
5267 cmov_optab = init_optab (UNKNOWN);
5268 cstore_optab = init_optab (UNKNOWN);
5269 push_optab = init_optab (UNKNOWN);
5270
5271 vec_extract_optab = init_optab (UNKNOWN);
5272 vec_set_optab = init_optab (UNKNOWN);
5273 vec_init_optab = init_optab (UNKNOWN);
上面,在init_optab,init_optabv左边,是形如XXX_optab的宏,它从optab_table选择对应的项。optab_table是具有optab类型的全局数组。
41 struct optab_handlers GTY(()) in optabs.h
42 {
43 enum insn_code insn_code;
44 rtx libfunc;
45 };
在其定义中,insn_code域指出在特定的机器模式(on a particular machine mode)下,如何为该操作生成指令。如果目标机器没有这样的指令,它就是CODE_FOR_nothing。域libfunc是可以用于执行该操作的库函数名。
47 struct optab GTY(()) in optabs.h
48 {
49 enum rtx_code code;
50 struct optab_handlers handlers[NUM_MACHINE_MODES];
51 };
52 typedef struct optab * optab;
在后端的章节里,我们将会知道insn_code描述了目标机器所能支持的指令(作为结果,insn_code必须由工具从机器描述文件产生)。而rtx_code描述了由前端产生的,与目标机器无关的,RTL形式的指令。结构体optab把rtx_code映射到insn_code。注意到handlers是一个数组,因为在目标机器,不同机器模式(mode)的操作,通常需要不同的指令。
4910 static inline optab
4911 init_optab (enum rtx_code code) in optabs.c
4912 {
4913 optab op = new_optab ();
4914 op->code = code;
4915 code_to_optab[(int) code] = op;
4916 return op;
4917 }
4921 static inline optab
4922 init_optabv (enum rtx_code code)
4923 {
4924 optab op = new_optab ();
4925 op->code = code;
4926 return op;
4927 }
这里操作名字后跟“v”的操作版本与没有“v”的版本共享同一个rtx-code,其区别在于,对于“v”版本,如果其计算结果发生溢出,会引发陷阱(trap)。这通过flag_trapv的值来选定适用的版本。
init_optabs (continue)
5274 /* Conversions. */
5275 sext_optab = init_convert_optab (SIGN_EXTEND);
5276 zext_optab = init_convert_optab (ZERO_EXTEND);
5277 trunc_optab = init_convert_optab (TRUNCATE);
5278 sfix_optab = init_convert_optab (FIX);
5279 ufix_optab = init_convert_optab (UNSIGNED_FIX);
5280 sfixtrunc_optab = init_convert_optab (UNKNOWN);
5281 ufixtrunc_optab = init_convert_optab (UNKNOWN);
5282 sfloat_optab = init_convert_optab (FLOAT);
5283 ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
在C++中,我们可以使用例如(int) f这样的语句进行类型转换。这干净方便,不需要考虑数据表达的细节。不过,这不是理所当然和免费的。必须为每个被允许的类型转换定义转换的方法。这就是convert_optab的来由。
上面,在init_convert_optab的左手边,宏XXX_optab在convert_optab_table中选择对应的项。convert_optab_table是具有convert_optab类型全局数组。
57 struct convert_optab GTY(()) in optabs.h
58 {
59 enum rtx_code code;
60 struct optab_handlers handlers[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
61 };
62 typedef struct convert_optab *convert_optab;
在其定义中,handlers是一个2维数组,记录了模式间的转换。
4930 static inline convert_optab
4931 init_convert_optab (enum rtx_code code) in optabs.c
4932 {
4933 convert_optab op = new_convert_optab ();
4934 op->code = code;
4935 return op;
4936 }
这里,movstr_optab记录了执行块移动的指令的insn_code。clrstr_optab记录了执行块清除的指令的insn_code。cmpstr_optab及cmpmem_optab记录了2种执行块比较的指令的insn_code。而reload_in_optab及reload_out_optab记录了,在执行特殊对象的输出及输入重新载入时(input and output reloads),所需要的指令的insn_code。它们提供了一个地方来传递一个工作寄存器(scratch register)。
init_optabs (continue)
5285 for (i = 0; i < NUM_MACHINE_MODES; i++)
5286 {
5287 movstr_optab[i] = CODE_FOR_nothing;
5288 clrstr_optab[i] = CODE_FOR_nothing;
5289 cmpstr_optab[i] = CODE_FOR_nothing;
5290 cmpmem_optab[i] = CODE_FOR_nothing;
5291
5292 #ifdef HAVE_SECONDARY_RELOADS
5293 reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
5294 #endif
5295 }
5296
5297 /* Fill in the optabs with the insns we support. */
5298 init_all_optabs ();
现在从前端看来,所有的optabs已经填入了相应的rtx_code,但前端不知道任何关于insn_code的事情,这是后端的事。为了完成optabs,后端特别地从机器描述文件,由genopinit工具产生了函数init_all_optabs。它帮助填入insn_code,下面是该函数的代码片段。
sext_optab->handlers[SImode][HImode].insn_code = CODE_FOR_extendhisi2;
sext_optab->handlers[HImode][QImode].insn_code = CODE_FOR_extendqihi2;
sext_optab->handlers[SImode][QImode].insn_code = CODE_FOR_extendqisi2;
…
setcc_gen_code[EQ] = CODE_FOR_seq;
setcc_gen_code[NE] = CODE_FOR_sne;
setcc_gen_code[GT] = CODE_FOR_sgt;
setcc_gen_code[GTU] = CODE_FOR_sgtu;
…
bcc_gen_fctn[EQ] = gen_beq;
bcc_gen_fctn[NE] = gen_bne;
bcc_gen_fctn[GT] = gen_bgt;
bcc_gen_fctn[GTU] = gen_bgtu;
上面,sext_optab从convert_optab_table中选出用于符号扩展的convert_optab。Handlers的第一个索引是目标模式,第二个是源模式。在赋值语句的右边是insn_code。
现在setcc_gen_code已经为正确的insn_code初始化,如果目标机器提供这样的指令。注意到。setcc_gen_code中不是所有的机器模式都能匹配到有意义的insn_code(即非CODE_FOR_nothing),这意味着这部分不能开放编码(open coded),而只能调用库例程。
再者,具有类型rtx_fun的全局数组bcc_gen_fctn给出测试条件,诸如EQ(等于),LT(小于),的方法。显然,gen_XXX也是从机器描述文件产生的,可以在insn_emit.c中找到其定义。
init_optabs (continue)
5300 /* Initialize the optabs with the names of the library functions. */
5301 init_integral_libfuncs (add_optab, "add", '3');
5302 init_floating_libfuncs (add_optab, "add", '3');
5303 init_integral_libfuncs (addv_optab, "addv", '3');
5304 init_floating_libfuncs (addv_optab, "add", '3');
5305 init_integral_libfuncs (sub_optab, "sub", '3');
5306 init_floating_libfuncs (sub_optab, "sub", '3');
5307 init_integral_libfuncs (subv_optab, "subv", '3');
5308 init_floating_libfuncs (subv_optab, "sub", '3');
5309 init_integral_libfuncs (smul_optab, "mul", '3');
5310 init_floating_libfuncs (smul_optab, "mul", '3');
5311 init_integral_libfuncs (smulv_optab, "mulv", '3');
5312 init_floating_libfuncs (smulv_optab, "mul", '3');
5313 init_integral_libfuncs (sdiv_optab, "div", '3');
5314 init_floating_libfuncs (sdiv_optab, "div", '3');
5315 init_integral_libfuncs (sdivv_optab, "divv", '3');
5316 init_integral_libfuncs (udiv_optab, "udiv", '3');
5317 init_integral_libfuncs (sdivmod_optab, "divmod", '4');
5318 init_integral_libfuncs (udivmod_optab, "udivmod", '4');
5319 init_integral_libfuncs (smod_optab, "mod", '3');
5320 init_integral_libfuncs (umod_optab, "umod", '3');
5321 init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
5322 init_integral_libfuncs (and_optab, "and", '3');
5323 init_integral_libfuncs (ior_optab, "ior", '3');
5324 init_integral_libfuncs (xor_optab, "xor", '3');
5325 init_integral_libfuncs (ashl_optab, "ashl", '3');
5326 init_integral_libfuncs (ashr_optab, "ashr", '3');
5327 init_integral_libfuncs (lshr_optab, "lshr", '3');
5328 init_integral_libfuncs (smin_optab, "min", '3');
5329 init_floating_libfuncs (smin_optab, "min", '3');
5330 init_integral_libfuncs (smax_optab, "max", '3');
5331 init_floating_libfuncs (smax_optab, "max", '3');
5332 init_integral_libfuncs (umin_optab, "umin", '3');
5333 init_integral_libfuncs (umax_optab, "umax", '3');
5334 init_integral_libfuncs (neg_optab, "neg", '2');
5335 init_floating_libfuncs (neg_optab, "neg", '2');
5336 init_integral_libfuncs (negv_optab, "negv", '2');
5337 init_floating_libfuncs (negv_optab, "neg", '2');
5338 init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
5339 init_integral_libfuncs (ffs_optab, "ffs", '2');
5340 init_integral_libfuncs (clz_optab, "clz", '2');
5341 init_integral_libfuncs (ctz_optab, "ctz", '2');
5342 init_integral_libfuncs (popcount_optab, "popcount", '2');
5343 init_integral_libfuncs (parity_optab, "parity", '2');
5344
5345 /* Comparison libcalls for integers MUST come in pairs, signed/unsigned. */
5346 init_integral_libfuncs (cmp_optab, "cmp", '2');
5347 init_integral_libfuncs (ucmp_optab, "ucmp", '2');
5348 init_floating_libfuncs (cmp_optab, "cmp", '2');
5349
5350 /* EQ etc are floating point only. */
5351 init_floating_libfuncs (eq_optab, "eq", '2');
5352 init_floating_libfuncs (ne_optab, "ne", '2');
5353 init_floating_libfuncs (gt_optab, "gt", '2');
5354 init_floating_libfuncs (ge_optab, "ge", '2');
5355 init_floating_libfuncs (lt_optab, "lt", '2');
5356 init_floating_libfuncs (le_optab, "le", '2');
5357 init_floating_libfuncs (unord_optab, "unord", '2');
接下来是初始化optab中handler的libfunc成员,这个域记录了可以执行由insn_code所指出的操作的库函数(但注意,这个库函数不一定存在)。
4991 static void
4992 init_integral_libfuncs (optab optable, const char *opname, int suffix) in optabs.c
4993 {
4994 int maxsize = 2*BITS_PER_WORD;
4995 if (maxsize < LONG_LONG_TYPE_SIZE)
4996 maxsize = LONG_LONG_TYPE_SIZE;
4997 init_libfuncs (optable, word_mode,
4998 mode_for_size (maxsize, MODE_INT, 0),
4999 opname, suffix);
5000 }
在4998行,mode_for_size在指定的类别中(这里是MODE_INT),找出具有指定精度(这里由maxsize 表示)的机器模式。
4955 static void
4956 init_libfuncs (optab optable, int first_mode, int last_mode, in optabs.c
4957 const char *opname, int suffix)
4958 {
4959 int mode;
4960 unsigned opname_len = strlen (opname);
4961
4962 for (mode = first_mode; (int) mode <= (int) last_mode;
4963 mode = (enum machine_mode) ((int) mode + 1))
4964 {
4965 const char *mname = GET_MODE_NAME (mode);
4966 unsigned mname_len = strlen (mname);
4967 char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
4968 char *p;
4969 const char *q;
4970
4971 p = libfunc_name;
4972 *p++ = '_';
4973 *p++ = '_';
4974 for (q = opname; *q; )
4975 *p++ = *q++;
4976 for (q = mname; *q; q++)
4977 *p++ = TOLOWER (*q);
4978 *p++ = suffix;
4979 *p = '/0';
4980
4981 optable->handlers[(int) mode].libfunc
4982 = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
4983 }
4984 }
在4981行之前,仅是构建库函数名。在4982行,在ggc(gcc垃圾收集器)管理的栈上分配字符串。以5301行代码为例,所声明的库函数有:__addqi3,__addhi3,__addsi3,__adddi3。不过这些库函数并没有实现,因为目标机器描述文件已经告诉了编译器,可以完成这个操作的指令的细节。
init_optabs (continue)
5359 /* Conversions. */
5360 init_interclass_conv_libfuncs (sfloat_optab, "float", MODE_INT, MODE_FLOAT);
5361 init_interclass_conv_libfuncs (sfix_optab, "fix", MODE_FLOAT, MODE_INT);
5362 init_interclass_conv_libfuncs (ufix_optab, "fixuns", MODE_FLOAT, MODE_INT);
对于类别间的转换,例如int到float,这涉及到数据表达形式的转换。需要由以下的 init_interclass_conv_libfuncs填充handlers。
5018 static void
5019 init_interclass_conv_libfuncs (convert_optab tab, const char *opname, in optabs.c
5020 enum mode_class from_class,
5021 enum mode_class to_class)
5022 {
5023 enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
5024 enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
5025 size_t opname_len = strlen (opname);
5026 size_t max_mname_len = 0;
5027
5028 enum machine_mode fmode, tmode;
5029 const char *fname, *tname;
5030 const char *q;
5031 char *libfunc_name, *suffix;
5032 char *p;
5033
5034 for (fmode = first_from_mode;
5035 fmode != VOIDmode;
5036 fmode = GET_MODE_WIDER_MODE (fmode))
5037 max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
5038
5039 for (tmode = first_to_mode;
5040 tmode != VOIDmode;
5041 tmode = GET_MODE_WIDER_MODE (tmode))
5042 max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
5043
5044 libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5045 libfunc_name[0] = '_';
5046 libfunc_name[1] = '_';
5047 memcpy (&libfunc_name[2], opname, opname_len);
5048 suffix = libfunc_name + opname_len + 2;
5049
5050 for (fmode = first_from_mode; fmode != VOIDmode;
5051 fmode = GET_MODE_WIDER_MODE (fmode))
5052 for (tmode = first_to_mode; tmode != VOIDmode;
5053 tmode = GET_MODE_WIDER_MODE (tmode))
5054 {
5055 fname = GET_MODE_NAME (fmode);
5056 tname = GET_MODE_NAME (tmode);
5057
5058 p = suffix;
5059 for (q = fname; *q; p++, q++)
5060 *p = TOLOWER (*q);
5061 for (q = tname; *q; p++, q++)
5062 *p = TOLOWER (*q);
5063
5064 *p = '/0';
5065
5066 tab->handlers[tmode][fmode].libfunc
5067 = init_one_libfunc (ggc_alloc_string (libfunc_name,
5068 p - libfunc_name));
5069 }
5070 }
同样,这里声明的大多数转换库函数都没有真正实现(参考libgcc2.c)。它们有对应的指令。
init_optabs (continue)
5364 /* sext_optab is also used for FLOAT_EXTEND. */
5365 init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
5366 init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
前面我们看到,单精度和双精度浮点数实际上是不同的表示方式,因而从单精度扩展到双精度也好,从双精度截短到单精度也好,本质上这是个转换。因此,也需要准备转换函数。
5077 static void
5078 init_intraclass_conv_libfuncs (convert_optab tab, const char *opname, in optabs.c
5079 enum mode_class class, bool widening)
5080 {
5081 enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
5082 size_t opname_len = strlen (opname);
5083 size_t max_mname_len = 0;
5084
5085 enum machine_mode nmode, wmode;
5086 const char *nname, *wname;
5087 const char *q;
5088 char *libfunc_name, *suffix;
5089 char *p;
5090
5091 for (nmode = first_mode; nmode != VOIDmode;
5092 nmode = GET_MODE_WIDER_MODE (nmode))
5093 max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
5094
5095 libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
5096 libfunc_name[0] = '_';
5097 libfunc_name[1] = '_';
5098 memcpy (&libfunc_name[2], opname, opname_len);
5099 suffix = libfunc_name + opname_len + 2;
5100
5101 for (nmode = first_mode; nmode != VOIDmode;
5102 nmode = GET_MODE_WIDER_MODE (nmode))
5103 for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
5104 wmode = GET_MODE_WIDER_MODE (wmode))
5105 {
5106 nname = GET_MODE_NAME (nmode);
5107 wname = GET_MODE_NAME (wmode);
5108
5109 p = suffix;
5110 for (q = widening ? nname : wname; *q; p++, q++)
5111 *p = TOLOWER (*q);
5112 for (q = widening ? wname : nname; *q; p++, q++)
5113 *p = TOLOWER (*q);
5114
5115 *p++ = '2';
5116 *p = '/0';
5117
5118 tab->handlers[widening ? wmode : nmode]
5119 [widening ? nmode : wmode].libfunc
5120 = init_one_libfunc (ggc_alloc_string (libfunc_name,
5121 p - libfunc_name));
5122 }
5123 }
同样这些转换库函数都没有实现,这些操作还是依赖机器描述文件给出的指令。
init_optabs (continue)
5368 /* Use cabs for double complex abs, since systems generally have cabs.
5369 Don't define any libcall for float complex, so that cabs will be used. */
5370 if (complex_double_type_node)
5371 abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
5372 = init_one_libfunc ("cabs");
5373
5374 /* The ffs function operates on `int'. */
5375 ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
5376 = init_one_libfunc ("ffs");
5377
5378 abort_libfunc = init_one_libfunc ("abort");
5379 memcpy_libfunc = init_one_libfunc ("memcpy");
5380 memmove_libfunc = init_one_libfunc ("memmove");
5381 bcopy_libfunc = init_one_libfunc ("bcopy");
5382 memcmp_libfunc = init_one_libfunc ("memcmp");
5383 bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
5384 memset_libfunc = init_one_libfunc ("memset");
5385 bzero_libfunc = init_one_libfunc ("bzero");
5386 setbits_libfunc = init_one_libfunc ("__setbits");
5387
5388 unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
5389 ? "_Unwind_SjLj_Resume"
5390 : "_Unwind_Resume");
5391 #ifndef DONT_USE_BUILTIN_SETJMP
5392 setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
5393 longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
5394 #else
5395 setjmp_libfunc = init_one_libfunc ("setjmp");
5396 longjmp_libfunc = init_one_libfunc ("longjmp");
5397 #endif
5398 unwind_sjlj_register_libfunc = init_one_libfunc ("_Unwind_SjLj_Register");
5399 unwind_sjlj_unregister_libfunc
5400 = init_one_libfunc ("_Unwind_SjLj_Unregister");
5401
5402 /* For function entry/exit instrumentation. */
5403 profile_function_entry_libfunc
5404 = init_one_libfunc ("__cyg_profile_func_enter");
5405 profile_function_exit_libfunc
5406 = init_one_libfunc ("__cyg_profile_func_exit");
5407
5408 gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
5409 gcov_init_libfunc = init_one_libfunc ("__gcov_init");
5410
5411 if (HAVE_conditional_trap)
5412 trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
5413
5414 /* Allow the target to add more libcalls or rename some, etc. */
5415 targetm.init_libfuncs ();
5416 }
在gcc的安装目录下有lib子目录,里面是编译器用到的库文件(当然,是根据gcc的源代码,在安装gcc时编译出来的)。使用nm工具,可以找出上面大多数的库函数名。5415行的钩子init_libfuncs使得目标机器有机会加入自己的库函数或重命名某些库函数,不过对于x86机器,这不需要。