GCC-3.4.6源代码学习笔记(169)

5.13.5.2.2.1.1.2.    确定输出节

找到或准备好了常量描述符之后,接着在 output_constant_def 中调用下面的函数,尝试在内存中输出这个常量。

 

2509 static void

2510 maybe_output_constant_def_contents (struct constant_descriptor_tree *desc, in varasm.c

2511                                int defer)

2512 {

2513   rtx symbol = XEXP (desc->rtl, 0);

2514   tree exp = desc->value;

2515

2516   if (flag_syntax_only )

2517     return ;

2518

2519   if (TREE_ASM_WRITTEN (exp))

2520     /* Already output; don't do it again.  */

2521     return ;

2522

2523   /* The only constants that cannot safely be deferred, assuming the

2524     context allows it, are strings under flag_writable_strings.  */

2525   if (defer && (TREE_CODE (exp) != STRING_CST || !flag_writable_strings ))

2526   {

2527      /* Increment n_deferred_constants if it exists. It needs to be at

2528       least as large as the number of constants actually referred to

2529       by the function. If it's too small we'll stop looking too early

2530       and fail to emit constants; if it's too large we'll only look

2531       through the entire function when we could have stopped earlier.  */

2532     if (cfun )

2533       n_deferred_constants ++;

2534     return ;

2535   }

2536

2537   output_constant_def_contents (symbol);

2538 }

 

如果已经发布了汇编代码, TREE_ASM_WRITTEN 将被设置,不需要再次发布。下面 2545 行的 SYMBOL_REF_DECL 是在 build_constant_desc 2454 行设置的常量节点的拷贝。为这个节点同样调用 compute_reloc_for_constant 来确定 reloc ,及 output_addressed_constants 输出其中所包含的常量。

 

2542 static void

2543 output_constant_def_contents (rtx symbol)                                                  in varasm.c

2544 {

2545   tree exp = SYMBOL_REF_DECL (symbol);

2546   const char *label = XSTR (symbol, 0);

2547   HOST_WIDE_INT size;

2548

2549   /* Make sure any other constants whose addresses appear in EXP

2550     are assigned label numbers.  */

2551   int reloc = compute_reloc_for_constant (exp);

2552

2553   /* Align the location counter as required by EXP's data type.  */

2554   int align = TYPE_ALIGN (TREE_TYPE (exp));

2555 #ifdef CONSTANT_ALIGNMENT

2556   align = CONSTANT_ALIGNMENT (exp, align);

2557 #endif

2558

2559   output_addressed_constants (exp);

2560

2561   /* We are no longer deferring this constant.  */

2562   TREE_ASM_WRITTEN (exp) = 1;

2563

2564   if (IN_NAMED_SECTION (exp))

2565     named_section (exp, NULL, reloc);

2566   else

2567     (*targetm .asm_out.select_section ) (exp, reloc, align);

2568

2569   if (align > BITS_PER_UNIT)

2570   {

2571     ASM_OUTPUT_ALIGN (asm_out_file , floor_log2 (align / BITS_PER_UNIT));

2572   }

2573

2574   size = int_size_in_bytes (TREE_TYPE (exp));

2575   if (TREE_CODE (exp) == STRING_CST)

2576     size = MAX (TREE_STRING_LENGTH (exp), size);

2577

2578   /* Do any machine/system dependent processing of the constant.  */

2579 #ifdef ASM_DECLARE_CONSTANT_NAME

2580   ASM_DECLARE_CONSTANT_NAME (asm_out_file , label, exp, size);

2581 #else

2582   /* Standard thing is just output label for the constant.  */

2583   ASM_OUTPUT_LABEL (asm_out_file , label);

2584 #endif /* ASM_DECLARE_CONSTANT_NAME */

2585

2586   /* Output the value of EXP.  */

2587   output_constant (exp, size, align);

2588 }

 

如果已经选定了输出的节( section ),对于 FUNCTION_DECL VAR_DECL 节点, IN_NANED_SECTION 返回 true 。否则调用目标平台钩子 select_section ,它指向下面的函数。

 

4792 void

4793 default_select_section (tree decl, int reloc,                                                   in varasm.c

4794                    unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)

4795 {

4796   bool readonly = false;

4797

4798   if (DECL_P (decl))

4799   {

4800     if (decl_readonly_section (decl, reloc))

4801       readonly = true;

4802   }

4803   else if (TREE_CODE (decl) == CONSTRUCTOR)

4804   {

4805     if (! ((flag_pic && reloc)

4806          || !TREE_READONLY (decl)

4807          || TREE_SIDE_EFFECTS (decl)

4808          || !TREE_CONSTANT (decl)))

4809       readonly = true;

4810   }

4811   else if (TREE_CODE (decl) == STRING_CST)

4812     readonly = !flag_writable_strings ;

4813   else if (! (flag_pic && reloc))

4814     readonly = true;

4815

4816   if (readonly)

4817     readonly_data_section ();

4818   else

4819     data_section ();

4820 }

 

上面断言 DECL_P 成立,如果 decl 是一个真正的 DECL 节点。而下面的函数确定 decl 是否是只读的。

 

4941 bool

4942 decl_readonly_section (tree decl, int reloc)                                                   in varasm.c

4943 {

4944   return decl_readonly_section_1 (decl, reloc, flag_pic );

4945 }

 

变量 flag_pic 保存了选项 –fpic/-fPIC –fpie/-fPIE (如果 –fpic/-fPIC 不出现)的值。【 6 】给出了关于这个选项的描述;

-fpic 产生适用于共享库的位置无关代码( position-independent code – PIC ),如果为目标机器提供支持。这样的代码通过一个全局偏移表( global offset table – GOT )访问所有的常量地址。动态加载器,在程序启动时,解析 GOT 项(动态加载器不是 GCC 的部分;它是操作系统的一部分)。对于链接的可执行映像,如果 GOT 的大小超出了机器指定的最大尺寸,会从链接器得到一个显示‘ -fpic ’不能工作的错误信息;在这个情形下,可使用‘ -fPIC ’重新编译。(这些最大值在 SPARC 上是 8k ,在 m68k RS/6000 上是 32k 386 没有这样的限制)。

位置无关代码要求特殊的支持,因此只在某些机器上可用。对于 386 GCC System V 提供 PIC 支持,但不支持 Sun 386i 。为 IBM RS/6000 产生的代码总是位置无关的。当设置了这个标记时,宏 __pic__ __PIC__ 被定义为 1

-fPIC 如果为目标机器提供支持,发布适用于动态链接的位置无关代码,并避免全局偏移表大小的限制。这个选项在 m68k PowerPC SPARC 上有重要作用。

位置无关代码要求特殊的支持,因此只在某些机器上可用。

当设置了这个标记时,宏 __pic__ __PIC__ 被定义为 2

-fpie

-fPIE 这些选项类似于‘ -fpic ’及‘ -fPIC ’,不过产生的位置无关代码只能被链入可执行映像。通常,当 GCC 选项‘ -pie ’在链接过程中将被使用时,使用这些选项。

-fpie ’及‘ -fPIE ’都会定义宏 __pie__ __PIE__ 。这些宏对应‘ -fpie ’具有值 1 ,对应‘ -fPIE ’具有值 2

 

4947 bool

4948 decl_readonly_section_1 (tree decl, int reloc, int shlib)                                  in varasm.c

4949 {

4950   switch (categorize_decl_for_section (decl, reloc, shlib))

4951   {

4952     case SECCAT_RODATA:

4953     case SECCAT_RODATA_MERGE_STR:

4954     case SECCAT_RODATA_MERGE_STR_INIT:

4955     case SECCAT_RODATA_MERGE_CONST:

4956     case SECCAT_SRODATA:

4957       return true;

4958       break;

4959     default :

4960       return false;

4961        break ;

4962   }

4963 }

 

section_category 的枚举值的名字中,片段“ _REL ”表示该节包含重定位数据,因此它们被聚集起来,那么动态链接器将访问更少内存页。而“ _RO ”表示该节包含只读数据。这对于预先链接( prelinking )是有用的,因为绝大多数重定位将不是动态地链接,并保持只读。另外“ _LOCAL ”表示该节包含对局部对象的重定位数据。这些重定位将被预先链接完全解析。

 

4862 static enum section_category

4863 categorize_decl_for_section (tree decl, int reloc, int shlib)                                    in varasm.c

4864 {

4865   enum section_category ret;

4866

4867   if (TREE_CODE (decl) == FUNCTION_DECL)

4868     return SECCAT_TEXT;

4869   else if (TREE_CODE (decl) == STRING_CST)

4870   {

4871     if (flag_writable_strings )

4872       return SECCAT_DATA;

4873     else

4874       return SECCAT_RODATA_MERGE_STR;

4875   }

4876   else if (TREE_CODE (decl) == VAR_DECL)

4877   {

4878     if (DECL_INITIAL (decl) == NULL

4879        || DECL_INITIAL (decl) == error_mark_node)

4880       ret = SECCAT_BSS;

4881     else if (! TREE_READONLY (decl)

4882           || TREE_SIDE_EFFECTS (decl)

4883           || ! TREE_CONSTANT (DECL_INITIAL (decl)))

4884     {

4885       if (shlib && (reloc & 2))

4886         ret = SECCAT_DATA_REL;

4887       else if (shlib && reloc)

4888         ret = SECCAT_DATA_REL_LOCAL;

4889       else

4890         ret = SECCAT_DATA;

4891     }

4892     else if (shlib && (reloc & 2))

4893       ret = SECCAT_DATA_REL_RO;

4894     else if (shlib && reloc)

4895       ret = SECCAT_DATA_REL_RO_LOCAL;

4896     else if (reloc || flag_merge_constants < 2)

4897       /* C and C++ don't allow different variables to share the same

4898         location. -fmerge-all-constants allows even that (at the

4899         expense of not conforming).  */

4900       ret = SECCAT_RODATA;

4901     else if (TREE_CODE (DECL_INITIAL (decl)) == STRING_CST)

4902       ret = SECCAT_RODATA_MERGE_STR_INIT;

4903     else

4904       ret = SECCAT_RODATA_MERGE_CONST;

4905   }

4906   else if (TREE_CODE (decl) == CONSTRUCTOR)

4907   {

4908     if ((shlib && reloc)

4909        || TREE_SIDE_EFFECTS (decl)

4910        || ! TREE_CONSTANT (decl))

4911       ret = SECCAT_DATA;

4912     else

4913       ret = SECCAT_RODATA;

4914   }

4915   else

4916     ret = SECCAT_RODATA;

4917

4918   /* There are no read-only thread-local sections.  */

4919   if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))

4920   {

4921     if (ret == SECCAT_BSS)

4922       ret = SECCAT_TBSS;

4923     else

4924       ret = SECCAT_TDATA;

4925   }

4926

4927   /* If the target uses small data sections, select it.  */

4928   else if ((*targetm .in_small_data_p) (decl))

4929   {

4930     if (ret == SECCAT_BSS)

4931       ret = SECCAT_SBSS;

4932     else if (targetm .have_srodata_section && ret == SECCAT_RODATA)

4933       ret = SECCAT_SRODATA;

4934     else

4935       ret = SECCAT_SDATA;

4936   }

4937

4938   return ret;

4939 }

 

除非使用选项‘ -fwritable-string ’,标记 flag_writable_strings false ,这时字符串被视为常量,可与只读数据放在一起。因此选定节 SECCAT_RODATA_MERGE_STR ,在该节中只读数据与字符串合并在一起。

而对于变量( VAR_DECL ),如果没有初始值,依照 C++ 语言的规范,该变量将放在 BSS 节( 4880 行)。如果对象的内容是可改变的( 4881~4883 行条件,注意 4883 行条件检查常量指针初始值的情况),那么如果 reloc 设置了第二位(对于该 VAR_DECL 节点 TREE_PUBLIC true ,参考 compute_reloc_for_constant )并且要求产生 PIC 代码,把该数据放入 SECCAT_DATA_REL 节;若然 reloc 只设置了第一位并且要求产生 PIC 代码,把该数据放入 SECCAT_DATA_REL_LOCAL 节。

4919 行, DECL_THREAD_LOCAL 0 表示使用线程的局部储存。而在 4928 行,钩子 in_small_data_p 判断该数据是否能放入所谓的小数据节( small data section )。这对于 RISC CPU (例如 PPC )尤为重要,一个具有形式“ Rx + 16bit ”的取址模式可以放入一条 32 RISC 指令中,而 32 位绝对地址就要使用混乱得多的周折,把地址放入一个寄存器,然后执行真正的存取。使用小数据节可以尽可能地产生“ Rx + 16bit ”的取址模式。不过, x86 不需要这样的概念。

回到 default_select_section ,如果选定的节是只读属性的,就调用下面的函数。

 

265  void

266  readonly_data_section (void)                                                                       in varasm.c

267  {

268  #ifde f READONLY_DATA_SECTION

269    READONLY_DATA_SECTION ();  /* Note this can call data_section.  */

270  #else

271  #ifdef READONLY_DATA_SECTION_ASM_OP

272    if (in_section != in_readonly_data)

273    {

274      i n_section = in_readonly_data;

275      fputs (READONLY_DATA_SECTION_ASM_OP, asm_out_file );

276      fputc ('/n', asm_out_file );

277    }

278  #else

279    text_section ();

280  #endif

281  #endif

282  }

 

如果目标平台规定了只读节的命名方式,就要定义宏 READONLY_DATA_SECTION 。而如果目标平台规定了识别只读数据的特定的汇编操作,则需要定义宏 READONLY_DATA_SECTION_ASM_OP 。对于 x86 ,这些宏都没定义,因此调用 279 行的 text_section

 

231  void

232  text_section (void)                                                                                     in varasm.c

233  {

234    if (in_section != in_text)

235      {

236        i n_section = in_text;

237        fprintf (asm_out_file , "%s/n", TEXT_SECTION_ASM_OP);

238      }

239  }

 

静态变量 in_section 记录当前正在写入节的类型。而 TEXT_SECTION_ASM_OP ,对于绝大多数平台,被定义为 ”/t.text”

如果不是只读数据,则是使用下面的函数。

 

243  void

244  data_section (void)                                                                                     in varasm.c

245  {

246    if (in_section != in_data)

247    {

248      i n_section = in_data;

249      if (flag_shared_data )

250      {

251  #ifdef SHARED_SECTION_ASM_OP

252        fprintf (asm_out_file , "%s/n", SHARED_SECTION_ASM_OP);

253  #else

254        fprintf (asm_out_file , "%s/n", DATA_SECTION_ASM_OP);

255  #endif

256      }

257      else

258        fprintf (asm_out_file , "%s/n", DATA_SECTION_ASM_OP);

259    }

260  }

 

标记 flag_shared_data 由选项 -fshared-data 设置,这个选项要求此次编译的数据和非 const 变量是共享数据,而不是私有数据。这种差别仅在某些操作系统上面有意义,那里的共享数据在同一个程序的若干进程间共享,而私有数据在每个进程内都有副件。上面可以看到如果定义了 SHARED_SECTION_ASM_OP ,共享数据对该系统才是有意义的。当前只有 IBM 370/MVS 370/OpenEdition 定义了这个宏。

 

你可能感兴趣的:(tree,merge,Constructor,output,alignment,Constants)