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

5.13.5.2.2.2.  变量

输出初始值后,回到 assemble_variable ,接下来处理对应的变量。

 

assemble_variable (continue)

 

1468   resolve_unique_section (decl, reloc, flag_data_sections );

 

上面的 flag_data_sections 由选项 –fdata-sections 设置,它连同选项 –ffunction-sections (设置 flag_function_sections )被用于下面的目的 [ 6

如果目标机器支持任意节,在输出文件中,把每个函数或数据项放在它自己的节中。该函数或数据项的名字确定了在输出文件中对应节的名字。

在那些链接器可以执行优化以提高指令空间中引用的局部性的系统上使用这些选项。大多数系统使用 ELF 目标格式,并且运行 Solaris 2 SPARC 处理器具有有这样优化的链接器。在未来, AIX 可能会具有这些优化。

仅当这样做会带来大的利益时,才使用这些选项。当你指定这些选项时,汇编器及链接器将构建更大的目标及执行文件,同时汇编器及链接器将运行得更慢。如果你指定了这个选项,你将不能在所有的系统上使用 gprof ,并且如果你同时指定这个选项及‘ -g ’,你可能会有调试的问题。

 

442  void

443  resolve_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED,         in varasm.c

444                      int flag_function_or_data_sections)

445  {

446    if (DECL_SECTION_NAME (decl) == NULL_TREE

447        && targetm .have_named_sections

448        && (flag_function_or_data_sections

449             || DECL_ONE_ONLY (decl)))

450      (*targetm .asm_out.unique_section) (decl, reloc);

451  }

 

这里假定没使用 –fdata-sections ,默认地, flag_data_sections 0 。而在 449 DECL_ONE_ONLY 是非 0 值,如果在多个编译单元中 decl 的拷贝需要被合并。对于 x86 芯片及 Linux OS ,在这里,这个断言返回 false

 

assemble_variable (continue)

 

1470   /* Handle uninitialized definitions.  */

1471

1472   /* If the decl has been given an explicit section name, then it

1473     isn't common, and shouldn't be handled as such.  */

1474   if (DECL_SECTION_NAME (decl) || dont_output_data)

1475     ;

1476   /* We don't implement common thread-local data at present.  */

1477   else if (DECL_THREAD_LOCAL (decl))

1478   {

1479     if (DECL_COMMON (decl))

1480       sorry ("thread-local COMMON data not implemented");

1481   }

1482   else if (DECL_INITIAL (decl) == 0

1483         || DECL_INITIAL (decl) == error_mark_node

1484         || (flag_zero_initialized_in_bss

1485           /* Leave constant zeroes in .rodata so they can be shared.  */

1486            && !TREE_READONLY (decl)

1487           && initializer_zerop (DECL_INITIAL (decl))))

1488   {

1489     unsigned HOST_WIDE_INT size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);

1490     unsigned HOST_WIDE_INT rounded = size;

1491

1492     /* Don't allocate zero bytes of common,

1493       since that means "undefined external" in the linker.  */

1494     if (size == 0)

1495       rounded = 1;

1496

1497     /* Round size up to multiple of BIGGEST_ALIGNMENT bits

1498       so that each uninitialized object starts on such a boundary.  */

1499     rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;

1500     rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)

1501               * (BIGGEST_ALIGNMENT / BITS_PER_UNIT));

1502      

1503 #if !defined (ASM_OUTPUT_ALIGNED_COMMON) && !defined (ASM_OUTPUT_ALIGNED_DECL_COMMON) && !defined (ASM_OUTPUT_ALIGNED_BSS)

1504     if ((unsigned HOST_WIDE_INT) DECL_ALIGN (decl) / BITS_PER_UNIT > rounded)

1505       warning ("%Jrequested alignment for '%D' is greater than "

1506                "implemented alignment of %d", decl, decl, rounded);

1507 #endif

1508

1509     /* If the target cannot output uninitialized but not common global data

1510       i n .bss, then we have to use .data, so fall through.  */

1511     if (asm_emit_uninitialised (decl, name, size, rounded))

1512       return ;

1513   }

 

因为 resolve_unique_section 在此处不做任何处理(如果需要,它将为 decl 选定一个独有的节),在 1474 行的 DECL_SECTION_NAME 返回 NULL

5.13.5.2.2.2.1.          发布汇编 未指定初始值

注意 don’t_output_data 0 。在 1484 行, flag_zero_initialized_in_bss 默认的是 1 ,它表示把 0 初始化的数据放入 bss 节( GCC 默认地把初始化为 0 的变量放入 BSS ,除非目标机器不支持 BSS )。

1267 行, DECL_COMMON 如果成立,表示该声明尽可能放入“ .comm ”节,这样多个未初始化的变量实例可以被合并。但是如果变量的 DECL_INITIAL 不是 error_mark_node ,该变量则不能放入“ .comm ”节。

 

1250 static bool

1251 asm_emit_uninitialised (tree decl, const char *name,                                     in varasm.c

1252                     unsigned HOST_WIDE_INT size ATTRIBUTE_UNUSED,

1253                     unsigned HOST_WIDE_INT rounded ATTRIBUTE_UNUSED)

1254 {

1255   enum

1256   {

1257     asm_dest_common,

1258     asm_dest_bss,

1259     asm_dest_local

1260   }

1261   destination = asm_dest_local;

1262

1263   /* ??? We should handle .bss via select_section mechanisms rather than

1264     via special target hooks. That would eliminate this special case.  */

1265   if (TREE_PUBLIC (decl))

1266   {

1267     if (!DECL_COMMON (decl))

1268 #ifdef ASM_EMIT_BSS

1269       destination = asm_dest_bss;

1270 #else

1271     return false;

1272 #endif

1273     else

1274       destination = asm_dest_common;

1275   }

1276

1277   if (destination == asm_dest_bss)

1278     globalize_decl (decl);

1279   resolve_unique_section (decl, 0, flag_data_sections );

 

通常没有初始值的全局变量(包括静态成员声明)的 DECL_COMMON 成立(注意静态变量的 TREE_PUBLIC 是不成立的,它将被输出到“ .local ”节),而具有初始值的声明则不成立。对于具有初始值的对象,在上面 1278 行,通过下面的函数输出声明的属性。

 

4355 static void

4356 globalize_decl (tree decl)                                                                             in varasm.c

4357 {

4358   const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0);

4359

4360 #if defined (ASM_WEAKEN_LABEL ) || defined (ASM_WEAKEN_DECL)

4361   if (DECL_WEAK (decl))

4362   {

4363     tree *p, t;

4364

4365 #ifdef ASM_WEAKEN_DECL

4366     ASM_WEAKEN_DECL (asm_out_file , decl, name, 0);

4367 #else

4368     ASM_WEAKEN_LABEL (asm_out_file , name);

4369 #endif

4370

4371     /* Remove this function from the pending weak list so that

4372        we do not emit multiple .weak directives for it.  */

4373     for (p = &weak_decls ; (t = *p) ; )

4374     {

4375         if (DECL_ASSEMBLER_NAME (decl) == DECL_ASSEMBLER_NAME (TREE_VALUE (t)))

4376         *p = TREE_CHAIN (t);

4377        else

4378         p = &TREE_CHAIN (t);

4379     }

4380     return ;

4381   }

4382 #endif

4383

4384   (*targetm .asm_out.globalize_label ) (asm_out_file , name);

4385 }

 

上面对于我们的目标机器,宏 ASM_WEAKEN_DECL 没有定义,而宏 ASM_WEAKEN_LABEL 则定义如下,输出所谓的弱声明的属性。

 

240   #define ASM_WEAKEN_LABEL (FILE, NAME)  /                                  in elfos.h

241    do                                    /

242    {                              /

243      fputs ("/t.weak/t", (FILE));    /

244      assemble_name ((FILE), (NAME));      /

245      fputc ('/n', (FILE));              /

246    }                              /

247    while (0)

 

对于非弱全局声明,则是通过 4384 行的钩子 globalize_label 输出。在我们的目标机器上,这个钩子函数是 default_globalize_label

 

5252 #ifdef GLOBAL_ASM_OP

5253 void

5254 default_globalize_label (FILE * stream, const char *name)                            in varasm.c

5255 {

5256   fputs (GLOBAL_ASM_OP, stream);

5257   assemble_name (stream, name);

5258   putc ('/n', stream);

5259 }

5260 #endif /* GLOBAL_ASM_OP */

 

GLOBAL_ASM_OP 在这里被定义为“ .globl ”(另一个兼容的形式是“ .global ”),它使得该符号对 ld GNU 链接器)可见。因此 default_globalize_label 的输出形如“ .globl       b ”,其中“ b ”是相应的变量名。

输出了对象的属性及其名字之后,接着由下面的代码确定并输出其所在节(如果需要改变当前的节)。

 

asm_emit_unintialised (continue)

 

1281   if (flag_shared_data )

1282   {

1283     switch (destination)

1284     {

1285 #ifdef ASM_OUTPUT_SHARED_BSS

1286       case asm_dest_bss:

1287         ASM_OUTPUT_SHARED_BSS (asm_out_file , decl, name, size, rounded);

1288         return ;

1289 #endif

1290 #ifdef ASM_OUTPUT_SHARED_COMMON

1291       case asm_dest_common:

1292         ASM_OUTPUT_SHARED_COMMON (asm_out_file , name, size, rounded);

1293         return ;

1294 #endif

1295 #ifdef ASM_OUTPUT_SHARED_LOCAL

1296       case asm_dest_local:

1297         ASM_OUTPUT_SHARED_LOCAL (asm_out_file , name, size, rounded);

1298         return ;

1299 #endif

1300       default :

1301         break ;

1302     }

1303   }

1304

1305   switch (destination)

1306   {

1307 #ifdef ASM_EMIT_BSS

1308     case asm_dest_bss:

1309       ASM_EMIT_BSS (decl, name, size, rounded);

1310       break ;

1311 #endif

1312     case asm_dest_common:

1313       ASM_EMIT_COMMON (decl, name, size, rounded);

1314       break ;

1315     case asm_dest_local:

1316       ASM_EMIT_LOCAL (decl, name, size, rounded);

1317       break ;

1318     default :

1319       abort ();

1320   }

1321

1322   return true;

1323 }

 

对于 x86/Linux ,上面带有“ SHARED ”字段的宏都没有定义,这表明 flag_shared_data 在这里其实不起作用。

ASM_EMIT_BSS ,对于 x86/Linux 目标机器,被定义为 asm_output_aligned_bss

 

501  static void

502  asm_output_aligned_bss (FILE *file, tree decl ATTRIBUTE_UNUSED,           in varasm.c

503                       const char *name, unsigned HOST_WIDE_INT size,

504                       int align)

505  {

506    bss_section ();

507    ASM_OUTPUT_ALIGN (file, floor_log2 (align / BITS_PER_UNIT));

508  #ifdef ASM_DECLARE_OBJECT_NAME

509    last_assemble_variable_decl = decl;

510    ASM_DECLARE_OBJECT_NAME (file, name, decl);

511  #else

512    /* Standard thing is just output label for the object.  */

513    ASM_OUTPUT_LABEL (file, name);

514  #endif /* ASM_DECLARE_OBJECT_NAME */

515    ASM_OUTPUT_SKIP (file, size ? size : 1);

516  }

 

首先通过下面的函数检查我们是否已经在“ .bss ”节,不是的话需要切换到“ .bss ”节。 BSS_SECTION_ASM_OP 被定义为“ /t.bss ”。

 

457  void

458  bss_section (void)                                                                                      in varasm.c

459  {

460    if (in_section != in_bss)

461    {

462       fprintf (asm_out_file , "%s/n", BSS_SECTION_ASM_OP);

463      i n_section = in_bss;

464    }

465  }

 

前面我们已经看过宏 ASM_OUTPUT_LABEL ,在那里它被用来输出标签。在这里我们要输出的是变量,在某些机器上,它们在本质上是不同的。这里, x86/Linux 定义了下面的宏来专门输出变量。

 

287  #define ASM_DECLARE_OBJECT_NAME (FILE, NAME, DECL)            /     in elfos.h

288    do                                                         /

289      {                                                      /

290        HOST_WIDE_INT size;                                /

291                                                          /

292        ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object");             /

293                                                          /

294        size_directive_output = 0;                       /

295        if (!flag_inhibit_size_directive                         /

296            && (DECL) && DECL_SIZE (DECL))                   /

297        {                                            /

298           size_directive_output = 1;                           /

299           size = int_size_in_bytes (TREE_TYPE (DECL));        /

300           ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, size);         /

301        }                                            /

302                                                          /

303        ASM_OUTPUT_LABEL (FILE, NAME);                       /

304      }                                                      /

305    while (0)

 

这里变量与标签的不同之处在于,变量有附加的说明,它由下面的宏输出。

 

186  #ifndef ASM_OUTPUT_TYPE_DIRECTIVE                                                 in defaults.h

187  #if defined TYPE_ASM_OP && defined TYPE_OPERAND_FMT

188  #define ASM_OUTPUT_TYPE_DIRECTIVE (STREAM, NAME, TYPE)   /

189    do                                                 /

190      {                                               /

191        fputs (TYPE_ASM_OP, STREAM);                /

192        assemble_name (STREAM, NAME);               /

193        fputs (", ", STREAM);                            /

194        fprintf (STREAM, TYPE_OPERAND_FMT, TYPE);             /

195        putc ('/n', STREAM);                      /

196      }                                               /

197    while (0)

198  #endif

199  #endif

 

上面的 TYPE_OPERAND_FMT elfos.h 中定义为“ @%s ”,而 TYPE_ASM_OP 则是“ /t.type/t ”。那么宏 ASM_OUTPUT_TYPE_DIRECTIVE 将输出形如:“ .type b, @object ”的内容,其中“ b ”是相应的变量名。

 

202  #ifndef ASM_OUTPUT_SIZE_DIRECTIVE

203  #ifdef SIZE_ASM_OP

204   #define ASM_OUTPUT_SIZE_DIRECTIVE (STREAM, NAME, SIZE)      /

205    do                                                  /

206      {                                               /

207        HOST_WIDE_INT size_ = (SIZE);                /

208        fputs (SIZE_ASM_OP, STREAM);                 /

209        assemble_name (STREAM, NAME);               /

210        fprintf (STREAM, ", " HOST_WIDE_INT_PRINT_DEC "/n", size_); /

211      }                                               /

212    while (0)

 

如果 flag_inhibit_size_directive 不是 0 ,表示禁止在 elf 中使用“ .size ”,它由编译选项 -finhibit-size-directive 设置,默认为 0 。只要不禁止,就使用 ASM_OUTPUT_SIZE_DIRECTIVE 输出变量的大小。这里 SIZE_ASM_OP 的定义是“ /t.size/t ”。输出的内容形如:“ .size   b, 4 ”,其中“ b ”是相应的变量名。

接着在 ASM_DECLARE_OBJECT_NAME 303 行调用 ASM_OUTPUT_LABLE ,把变量名输出为标签。然后在 asm_output_aligned_bss 515 行,由 ASM_OUTPUT_SKIP 输出形如“ .zero     4 ”的缺省初始值,其中“ 4 ”是变量的大小。

若要输出到“ .comm ”节,在这里,其输出宏 ASM_EMIT_COMMON 被定义为宏 ASM_OUTPUT_ALIGNED_COMMON

 

164  #undef   ASM_OUTPUT_ALIGNED_COMMON

165  #define ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN)/ in elfos.h

166    do                                                                /

167      {                                                             /

168        fprintf ((FILE), "%s", COMMON_ASM_OP);                      /

169        assemble_name ((FILE), (NAME));                              /

170         fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u/n",           /

171                (SIZE), (ALIGN) / BITS_PER_UNIT);                /

172      }                                                             /

173    while (0)

 

上面的 COMMON_ASM_OP 被定义为“ /t.comm/t ”,最终的输出形如“ .comm  b,4,4 ”,其中“ b ”是相应的变量名,第一个“ 4 ”是变量大小,后面的“ 4 ”是变量的对齐量。注意这里不会输出变量名的标签,及默认的初始值。

同样,对于局部变量(注意,包括静态变量), ASM_EMIT_LOCAL 在这里被定义为宏 ASM_OUTPUT_ALIGNED_LOCAL

 

182  #undef   ASM_OUTPUT_ALIGNED_LOCAL

183  #define ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN)      / in elfos.h

184    do                                                         /

185      {                                                      /

186        fprintf ((FILE), "%s", LOCAL_ASM_OP);                    /

187        assemble_name ((FILE), (NAME));                       /

188        fprintf ((FILE), "/n");                             /

189        ASM_OUTPUT_ALIGNED_COMMON (FILE, NAME, SIZE, ALIGN);      /

190      }                                                      /

191    while (0)

 

在这里, LOCAL_ASM_OP 的定义是“ /t.local/t ”,因此这里的输出形如:

.local a

.comm  a,4,4

 

5.13.5.2.2.2.2.          发布汇编 指定初始值

如果全局 / 静态变量具有初始值,则来到这里。首先由下面 1524 行的 variable_section 选出目标节(参见 确定输出节 )。

 

assemble_variable (continue)

 

1515   /* Handle initialized definitions.

1516     Also handle uninitialized global definitions if -fno-common and the

1517     target doesn't support ASM_OUTPUT_BSS.  */

1518

1519   /* First make the assembler name(s) global if appropriate.  */

1520   if (TREE_PUBLIC (decl) && DECL_NAME (decl))

1521     globalize_decl (decl);

1522

1523   /* Switch to the appropriate section.  */

1524   variable_section (decl, reloc);

1525

1526   /* dbxout.c needs to know this.  */

1527   if (in_text_section ())

1528     DECL_IN_TEXT_SECTION (decl) = 1;

1529

1530   /* Output the alignment of this data.  */

1531   if (align > BITS_PER_UNIT)

1532   {

1533     ASM_OUTPUT_ALIGN (asm_out_file ,

1534                           floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT));

1535   }

1536

1537   /* Do any machine/system dependent processing of the object.  */

1538 #ifdef ASM_DECLARE_OBJECT_NAME

1539   last_assemble_variable_decl = decl;

1540   ASM_DECLARE_OBJECT_NAME (asm_out_file , name, decl);

1541 #else

1542   /* Standard thing is just output label for the object.  */

1543   ASM_OUTPUT_LABEL (asm_out_file , name);

1544 #endif /* ASM_DECLARE_OBJECT_NAME */

1545

1546   if (!dont_output_data)

1547   {

1548     if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)

1549       /* Output the actual data.  */

1550       output_constant (DECL_INITIAL (decl),

1551                     tree_low_cst (DECL_SIZE_UNIT (decl), 1),

1552                     align);

1553     else

1554       /* Leave space for it.  */

1555       assemble_zeros (tree_low_cst (DECL_SIZE_UNIT (decl), 1));

1556   }

1557 }

 

余下的过程与我们上面所见非常相似。注意缺省初始化常量,它们在 1555 行处理。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值