After outputting the initializer(s), back assemble_variable , next output the variable.
assemble_variable (continue)
1468 resolve_unique_section (decl, reloc, flag_data_sections );
Above, flag_data_sections gets value of switch –fdata-sections, tegother with switch –ffunction-sections (in flag_function_sections ) are used for following purpose[6] :
Place each function or data item into its own section in the output file if the target supports arbitrary sections. The name of the function or the name of the data item determines the section’s name in the output file. Use these options on systems where the linker can perform optimizations to improve locality of reference in the instruction space. Most systems using the ELF object format and SPARC processors running Solaris 2 have linkers with such optimizations. AIX may have these optimizations in the future. Only use these options when there are significant benefits from doing so. When you specify these options, the assembler and linker will create larger object and executable files and will also be slower. You will not be able to use gprof on all systems if you specify this option and you may have problems with debugging if you specify both this option and ‘-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 }
Here assuming –fdata-sections is not present, by default, flag_data_sections is 0. And at line 449 above DECL_ONE_ONLY is nonzero if copies of decl in multiple translation units should be merged. For x86 chip and Linux OS, at this point, this predicate returns 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 }
Because here resolve_unique_section doesn’t any processing (if required, it will select an unique section for decl ), DECL_SECTION_NAME at line 1474 returns NULL.
5.13.5.2.2.2.1. Output assemble – variable without initializer
Note that don’t_output_data is 0. At line 1484, flag_zero_initialized_in_bss by default is 1, it indicates to put zero initialized data in the bss section (GCC by default puts variable initialized to 0 into BSS section, unless the target can’t support it).
At line 1267, if DECL_COMMON holds, means putting the declaration into “.comm” section as possible, thus multiple copies of this uninitialized variable cam be merged. But if its DECL_INITIAL isn’t error_mark_node, the declaration can’t be put into “.comm” section.
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 );
Usually, uninitialized global variable (includes static member) has DECL_COMMON set (note that TREE_PUBLIC of static variable is not TRUE, it will be output into “.local” section), but not for declarations having initializer. For object having initialzier, above at line 1278, outputs its property by below function.
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 }
Above for our target machine, macro ASM_WEAKEN_DECL isn’t defined, and macro ASM_WEAKEN_LABEL has below definition, it outputs the property of weak declaration.
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)
For non-weak global variable, it is output by hook globalize_label at line 4384. On our target machine, the function is 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 is defined as “.globl” here (another compatible one is “.global”), it makes the symbol visible to ld (GNU linker). So the output of default_globalize_label has form “.globl b”, in which “b” is the variable name.
After outputting the property and the name, below code determines the section to output the variable and output the section information (if needs to swap current section).
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 }
For x86/Linux, above macros containing “SHARED” field aren’t defined, which indicates at here flag_shared_data does not work.
Macro ASM_EMIT_BSS, for x86/Linux target, is defined by 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 }
First via below function to check if we are already in “.bss” section, swap to “.bss” section if it is not. BSS_SECTION_ASM_OP is “/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 }
Before we have seen macro ASM_OUTPUT_LABEL, there it is used to output label. Here what output is variable, in some machines, they are different in nature. Here, x86/Linux defines following macros to output variables specially.
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)
Here the difference between variable and label is that, variable has additional description which is output by below macro.
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
Above TYPE_OPERAND_FMT in elfos.h has definition “@%s”, and TYPE_ASM_OP is “/t.type/t”. SO macro ASM_OUTPUT_TYPE_DIRECTIVE will output some like: “.type b, object”, in which “b” is the variable name.
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)
If flag_inhibit_size_directive is nonzero, it means to prohibit “.size” in elf format, it is set by option “-finhibit-size-directive”, and the default value is 0. Unless prohibit, using ASM_OUTPUT_SIZE_DIRECTIVE to output the size of the variable. HereSIZE_ASM_OP’s definition is “/t.size/t”. The content output looks like: ”.size b, 4”, in which “b” is the variable name.
Next in ASM_DECLARE_OBJECT_NAME at line 303 invokes ASM_OUTPUT_LABLE to output the variable name as label, then in asm_output_aligned_bss at line 515, by ASM_OUTPUT_SKIP output default initializer like “.zero 4”, in which “4” is the size of the variable.
If it needs be output into “.comm” section, here the output macro ASM_EMIT_COMMON is defined as 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)
Above COMMON_ASM_OP is “/t.comm/t”, at last the output looks like “.comm b,4,4”, in which “b” is the variable name, the first “4” is the variable size, and the later “4” is the alignment .Note that here it won't output the label of the variable name and the default initializer.
Similarly, for local variable (note, includes static vairable), ASM_EMIT_LOCAL at here is defined as 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)
Here, LOCAL_ASM_OP is “/t.local/t”, so the output looks like:
.local a
.comm a,4,4
5.13.5.2.2.2.2. Output assemble – variable with initializer
If global/static variable has initializer, thus coming here. First, below at line 1524, variable_section selects the target section (refer to Select output 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 }
The rest procedure is very similar with that we see previously. Note that constant without initializer is handled at line 1555.