GCC-3.4.6源代码学习笔记(172)
2011-03-12 15:29
399 查看
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
】
:
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
行处理。
变量
输出初始值后,回到
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 ’,你可能会有调试的问题。 |
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
行处理。
相关文章推荐
- GCC-3.4.6源代码学习笔记(38)
- GCC-3.4.6源代码学习笔记 (100 续)
- GCC-3.4.6源代码学习笔记(147)
- GCC-3.4.6源代码学习笔记(72)
- GCC-3.4.6源代码学习笔记(121)
- GCC-3.4.6源代码学习笔记 (105)
- GCC-3.4.6源代码学习笔记(82)
- GCC-3.4.6源代码学习笔记(162)
- GCC-3.4.6源代码学习笔记(30)
- GCC-3.4.6源代码学习笔记(13)
- GCC-3.4.6源代码学习笔记(36)
- GCC-3.4.6源代码学习笔记(16)
- GCC-3.4.6源代码学习笔记(51)
- GCC-3.4.6源代码学习笔记(76)
- GCC-3.4.6源代码学习笔记(153)
- GCC-3.4.6源代码学习笔记(161)
- GCC-3.4.6源代码学习笔记(25续1)
- GCC-3.4.6源代码学习笔记(107)
- GCC-3.4.6源代码学习笔记(113)
- GCC-3.4.6源代码学习笔记(27)