GCC-3.4.6源代码学习笔记(172)
来源:互联网 发布:宁波每日新房成交数据 编辑:程序博客网 时间:2024/06/06 03:58
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, intreloc ATTRIBUTE_UNUSED, in varasm.c
444 intflag_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 /* Handleuninitialized definitions. */
1471
1472 /* If the decl has been given an explicitsection name, then it
1473 isn't common, and shouldn't be handled assuch. */
1474 if (DECL_SECTION_NAME (decl) ||dont_output_data)
1475 ;
1476 /* We don'timplement 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 notimplemented");
1481 }
1482 else if (DECL_INITIAL (decl) == 0
1483 || DECL_INITIAL (decl) ==error_mark_node
1484 || (flag_zero_initialized_in_bss
1485 /* Leaveconstant 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 allocatezero bytes of common,
1493 since that means "undefinedexternal" in the linker. */
1494 if (size == 0)
1495 rounded = 1;
1496
1497 /* Round size upto multiple of BIGGEST_ALIGNMENT bits
1498 so that each uninitialized object startson 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 targetcannot output uninitialized but not common global data
1510 in .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 sizeATTRIBUTE_UNUSED,
1253 unsigned HOST_WIDE_INTrounded 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 shouldhandle .bss via select_section mechanisms rather than
1264 via special target hooks. That wouldeliminate 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 #ifdefined (ASM_WEAKEN_LABEL)|| defined (ASM_WEAKEN_DECL)
4361 if (DECL_WEAK (decl))
4362 {
4363 tree *p, t;
4364
4365 #ifdefASM_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 thisfunction 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 #ifdefASM_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 #ifdefASM_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 intalign)
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 theobject. */
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 in_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 && definedTYPE_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 #defineASM_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 /* Handleinitialized definitions.
1516 Also handle uninitialized globaldefinitions if -fno-common and the
1517 target doesn't support ASM_OUTPUT_BSS. */
1518
1519 /* First make the assembler name(s) global ifappropriate. */
1520 if (TREE_PUBLIC (decl) && DECL_NAME(decl))
1521 globalize_decl(decl);
1522
1523 /* Switch to theappropriate section. */
1524 variable_section (decl, reloc);
1525
1526 /* dbxout.c needsto know this. */
1527 if (in_text_section ())
1528 DECL_IN_TEXT_SECTION (decl) = 1;
1529
1530 /* Output thealignment 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 anymachine/system dependent processing of the object. */
1538 #ifdefASM_DECLARE_OBJECT_NAME
1539 last_assemble_variable_decl = decl;
1540 ASM_DECLARE_OBJECT_NAME(asm_out_file,name, decl);
1541 #else
1542 /* Standard thing isjust 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 theactual data. */
1550 output_constant(DECL_INITIAL (decl),
1551 tree_low_cst(DECL_SIZE_UNIT (decl), 1),
1552 align);
1553 else
1554 /* Leave spacefor it. */
1555 assemble_zeros(tree_low_cst (DECL_SIZE_UNIT (decl), 1));
1556 }
1557 }
余下的过程与我们上面所见非常相似。注意缺省初始化常量,它们在1555行处理。
- GCC-3.4.6源代码学习笔记(172)
- GCC-3.4.6源代码学习笔记 (100)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记 (102)
- GCC-3.4.6源代码学习笔记 (103)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记 (106)
- GCC-3.4.6源代码学习笔记(166)
- GCC-3.4.6源代码学习笔记
- GCC-3.4.6源代码学习笔记(6)
- GCC-3.4.6源代码学习笔记(1)
- GCC-3.4.6源代码学习笔记(2)
- GCC-3.4.6源代码学习笔记(3)
- GCC-3.4.6源代码学习笔记(4)
- GCC-3.4.6源代码学习笔记(5)
- GCC-3.4.6源代码学习笔记(7)
- GCC-3.4.6源代码学习笔记(8)
- js遮罩层
- js遮罩层
- Windows CE虚拟内存
- 关于C++中函数指针的使用(包含对typedef用法的讨论)
- C 如何检测内存出错
- GCC-3.4.6源代码学习笔记(172)
- 孩子为什么不听话?因为你不会批评!
- sqlserver 数据转换 asp.net
- STM32 GPIO
- Studying note of GCC-3.4.6 source (172)
- 资源函数
- SCU 2011 warmup contest 5
- 摘抄一些函数
- 《人生六部书——处世经典 之方圆处世》