您的位置:首页 > 编程语言

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

2010-07-16 09:57 633 查看
4.3.1.7.5.6. 创建内建函数节点
4.3.1.7.5.6.1. 概览
现在是时候创建内建函数的节点了。同样的,这次我们仍然需要定义一个宏,从定义文件– builtins.def 来产生代码。

c_common_nodes_and_builtins (continue)

3431 #define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, /
3432 BOTH_P, FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT) /
3433 if (NAME) /
3434 { /
3435 tree decl; /
3436 /
3437 if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0) /
3438 abort (); /
3439 /
3440 if (!BOTH_P) /
3441 decl = builtin_function (NAME, builtin_types[TYPE], ENUM, /
3442 CLASS, /
3443 (FALLBACK_P /
3444 ? (NAME + strlen ("__builtin_")) /
3445 : NULL), /
3446 built_in_attributes[(int) ATTRS]); /
3447 else /
3448 decl = builtin_function_2 (NAME, /
3449 NAME + strlen ("__builtin_"), /
3450 builtin_types[TYPE], /
3451 builtin_types[LIBTYPE], /
3452 ENUM, /
3453 CLASS, /
3454 FALLBACK_P, /
3455 NONANSI_P, /
3456 built_in_attributes[(int) ATTRS]); /
3457 /
3458 built_in_decls[(int) ENUM] = decl; /
3459 if (IMPLICIT) /
3460 implicit_built_in_decls[(int) ENUM] = decl; /
3461 }
3462 #include "builtins.def"
3463 #undef DEF_BUILTIN
3464
3465 (*targetm.init_builtins) ();
3466
3467 main_identifier_node = get_identifier ("main");
3468 }

对于每个内建函数,这个宏都会被调用一次。ENUM将是类型enum built_in_function,表示哪个内建函数要被处理。NAME是表示内建函数名的字符串(总是以__builtin_开头)。CLASS是类型enum built_in_class,表示将处理的内建函数的种类。
某些内建函数实际上是2个独立的函数。例如,对于strcmp有2个内建函数,__builtin_strcmp及strcmp本身。2个函数的行为是相同的。其他内建函数则仅定义了__builtin 变体。如果BOTH_P 是TRUE,那么这个内建函数就有2个变体;否则它只有第一个变体。
TYPE表示函数的类型。这个符号对应于来自builtin-types.def的枚举值。如果BOTH_P是true,那么LIBTYPE就是非__builtin_变体的类型。否则,LIBTYPE将被忽略。
如果FALLBACK_P是true那么,如果出于某些原因,编译器不能直接展开这个内建函数,它将调用对应的库函数(不带__builtin_前缀的那个)。
如果NONANSI_P是true,那么非__builtin_变体不是一个ANSI/ISO库函数,并且我们应该假定,当遵从ANSI模式编译时,它不存在。
ATTRs是一个定义在builtin-attrs.def中的属性链,它描述了这个内建函数的属性。
IMPLICIT则指出编译器是否可以隐含地产生内建函数。例如C90保留了函数floorf,但没有定义其含义。当用户使用floorf时,我们假定floorf具有我们所期望的含义,但是我们不能简单地通过简化floor((double)float)来生成floorf,因为运行时不需要实现它。
为了看清产生的过程,我们以下面的内建函数作为例子。

484 DEF_LIB_BUILTIN (BUILT_IN_VPRINTF, "vprintf", BT_FN_INT_CONST_STRING_VALIST_ARG, ATTR_FORMAT_PRINTF_1_0)

80 #define DEF_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) /
81 DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, /
82 true, true, false, ATTRS, true)

为了实现展开,我们还需要另外2个宏。一个用于定义内建函数的枚举值。

90 #define DEF_BUILTIN(ENUM, N, C, T, LT, B, F, NA, AT, IM) ENUM, in tree.h
91 enum built_in_function
92 {
93 #include "builtins.def"
94
95 /* Upper bound on non-language-specific builtins. */
96 END_BUILTINS
97 };
98 #undef DEF_BUILTIN

另一个用于为函数产生名字字符串。

63 /* Define the names of the builtin function types and codes. */ in builtins.c
64 const char *const built_in_class_names[4]
65 = {"NOT_BUILT_IN", "BUILT_IN_FRONTEND", "BUILT_IN_MD", "BUILT_IN_NORMAL"};
66
67 #define DEF_BUILTIN(X, N, C, T, LT, B, F, NA, AT, IM) #X,
68 const char *const built_in_names[(int) END_BUILTINS] =
69 {
70 #include "builtins.def"
71 };
72 #undef DEF_BUILTIN
4.3.1.7.5.6.2. 创建FUNCTION_DECL节点
内建函数vprintf的BOTH_P是true,表明它有2个变体,一个是builtin,另一个是库函数(严格的说,是库函数vprintf的中间形式的声明,它链接到库函数vprintf)。这个内建函数需要builtin_function_2来创建它的2个变体。另外,vprintf的IMPLICIT为true,产生出来的builtin变体还将设置入implicit_built_in_decls,这是运行时所要求支持的函数集。实际上,在builtin.def文件中,内建函数分为以下几组:

69 #define DEF_GCC_BUILTIN(ENUM, NAME, TYPE, ATTRS) /
70 DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, BT_LAST, /
71 false, false, false, ATTRS, true)

这是由编译器提供的GCC内建函数(例如__builtin_saveregs),但没有对应的标准库的函数。
上例中的DEF_LIB_BUILTIN,是ANSI/ISO 标准库函数的等价内建函数(例如__builtin_strchr)。除了“__builtin”版本,我们还要创建普通版本(例如,strchr)。如果在使用内建函数时,我们不能计算出结果,我们将转交给标准库的版本。

89 #define DEF_EXT_LIB_BUILTIN(ENUM, NAME, TYPE, ATTRS) /
90 DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, /
91 true, true, true, ATTRS, false)

类似于DEF_LIB_BUILTIN,除了函数不是由ANSI/ISO C指定的。因而,当我们完全遵循标准时,我们忽略那些不以__builtin开头的库函数(不创建)。

96 #define DEF_C99_BUILTIN(ENUM, NAME, TYPE, ATTRS) /
97 DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, /
98 true, true, !flag_isoc99, ATTRS, TARGET_C99_FUNCTIONS)

类似于DEF_LIB_BUILTIN,除了函数只是C99或更高版本的一部分。

104 #define DEF_C99_C90RES_BUILTIN(ENUM, NAME, TYPE, ATTRS) /
105 DEF_BUILTIN (ENUM, "__builtin_" NAME, BUILT_IN_NORMAL, TYPE, TYPE, /
106 true, true, !flag_isoc99, ATTRS, TARGET_C99_FUNCTIONS)

由C99指定,而C90则保留其名字作将来使用,的内建函数。在C90中,我们可以仍然识别这些内建函数,但不能隐含地生成它们的库函数版本。
从这些宏,我们可以清楚地看到implicit_built_in_decls将包含由DEF_GCC_BUILTIN,DEF_LIB_BUILTIN,DEF_C99_BUILTIN,DEF_C99_C90RES_BUILTIN(后2个在运行C99编译器时)产生的内建函数。
对于构建内建函数vprintf,在其对builtin_function_2的调用中,参数值如下:
builtin_name - “__builtin_vprintf”
name - “vprintf”
builtin_type - builtin_types [BT_FN_INT_CONST_STRING_VALIST_ARG]
type - builtin_types [BT_FN_INT_CONST_STRING_VALIST_ARG]
function_code - BUILT_IN_VPRINTF
class - BUILT_IN_NORMAL
library_name_p - true
nonansi_p - false
attrs - built_in_attributes [ATTR_FORMAT_PRINTF_1_0]

3537 static tree
3538 builtin_function_2 (const char *builtin_name, const char *name, in c-common.c
3539 tree builtin_type, tree type, int function_code,
3540 enum built_in_class class, int library_name_p,
3541 int nonansi_p, tree attrs)
3542 {
3543 tree bdecl = NULL_TREE;
3544 tree decl = NULL_TREE;
3545
3546 if (builtin_name != 0)
3547 bdecl = builtin_function (builtin_name, builtin_type, function_code,
3548 class, library_name_p ? name : NULL, attrs);
3549
3550 if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
3551 && !(nonansi_p && flag_no_nonansi_builtin))
3552 decl = builtin_function (name, type, function_code, class, NULL, attrs);
3553
3554 return (bdecl != 0 ? bdecl : decl);
3555 }

编译选项-fno-builtin可以禁止产生对应于标准库函数的内建函数(flag_no_builtin不为0)。更进一步,可以通过编译选项-fno-builtin-XXX来禁止某个标准库函数的内建函数(函数builtin_function_disabled_p识别指定的内建函数是否被禁止)。下面我们以__builtin版本的内建函数为例,在其调builtin_function时,各参数值是:
name - “__builtin_vprintf”
type - builtin_types [BT_FN_INT_CONST_STRING_VALIST_ARG]
code - BUILT_IN_VPRINTF
class - BUILT_IN_NORMAL
libname - “vprintf”
attrs - built_in_attributes [ATTR_FORMAT_PRINTF_1_0]

3278 tree
3279 builtin_function (const char* name, in decl.c
3280 tree type,
3281 int code,
3282 enum built_in_class class,
3283 const char* libname,
3284 tree attrs)
3285 {
3286 /* All builtins that don't begin with an '_' should additionally
3287 go in the 'std' namespace. */
3288 if (name[0] != '_')
3289 {
3290 push_namespace (std_identifier);
3291 builtin_function_1 (name, type, std_node, code, class, libname, attrs);
3292 pop_namespace ();
3293 }
3294
3295 return builtin_function_1 (name, type, NULL_TREE, code,
3296 class, libname, attrs);
3297 }

注意,如果是标准库函数的内建函数,因为对应的库函数在std名字空间内,我们亦要在std名字空间中进行声明。继续__builtin版本的内建函数,调用builtin_function_1的参数值是:
name - “__builtin_vprintf”
type - builtin_types [BT_FN_INT_CONST_STRING_VALIST_ARG]
context - NULL_TREE
code - BUILT_IN_VPRINTF
class - BUILT_IN_NORMAL
libname - “vprinft”
attrs - built_in_attributes [ATTR_FORMAT_PRINTF_1_0]
注意context是NULL——这个声明是在全局名字空间中。

3225 static tree
3226 builtin_function_1 (const char* name, in decl.c
3227 tree type,
3228 tree context,
3229 int code,
3230 enum built_in_class class,
3231 const char* libname,
3232 tree attrs)
3233 {
3234 tree decl = build_library_fn_1 (get_identifier (name), ERROR_MARK, type);
3235 DECL_BUILT_IN_CLASS (decl) = class;
3236 DECL_FUNCTION_CODE (decl) = code;
3237 DECL_CONTEXT (decl) = context;

builtin_function_1首先调用build_library_fn_1来创建FUNCTION_DECL节点。注意到参数operator_code是ERROR_MAR,它被设置到SET_OVERLOADED_OPERATOR_CODE来表示该函数不是重载操作符。

3302 static tree
3303 build_library_fn_1 (tree name, enum tree_code operator_code, tree type) in decl.c
3304 {
3305 tree fn = build_lang_decl (FUNCTION_DECL, name, type);
3306 DECL_EXTERNAL (fn) = 1;
3307 TREE_PUBLIC (fn) = 1;
3308 DECL_ARTIFICIAL (fn) = 1;
3309 TREE_NOTHROW (fn) = 1;
3310 SET_OVERLOADED_OPERATOR_CODE (fn, operator_code);
3311 SET_DECL_LANGUAGE (fn, lang_c);
3312 return fn;
3313 }

在上面3308行,DECL_ARTIFICIAL被设置为1,表示该DECL节点代表一个“编译器造”的节点。而设置TREE_NOTHROW则表示该函数在调用过程中不会抛出异常。
4.3.1.7.5.6.3. 把FUNCTION_DECL加入当前名字空间
接下来,把生成的FUNCTION_DECL节点加入到当前的名字空间,使其生效。

builtin_function_1 (continue)

3293 pushdecl (decl);

566 tree
567 pushdecl (tree x) in name-lookup.c
568 {
569 tree t;
570 tree name;
571 int need_new_binding;
572
573 timevar_push (TV_NAME_LOOKUP);
574
575 need_new_binding = 1;
...
604 name = DECL_NAME (x);
605 if (name)
606 {
607 int different_binding_level = 0;
608
609 if (TREE_CODE (x) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (x))
610 check_default_args (x);
611
612 if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
613 name = TREE_OPERAND (name, 0);
614
615 /* In case this decl was explicitly namespace-qualified, look it
616 up in its namespace context. */
617 if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())
618 t = namespace_binding (name, DECL_CONTEXT (x));
619 else
620 t = lookup_name_current_level (name);

C/C++要求,当给一个参数声明缺省值时,跟随其后的参数都应该给予缺省值。否则将会给出错误信息。对此,check_default_args检查声明是否有效。

2948 void
2949 check_default_args (tree x) in decl2.c
2950 {
2951 tree arg = TYPE_ARG_TYPES (TREE_TYPE (x));
2952 bool saw_def = false;
2953 int i = 0 - (TREE_CODE (TREE_TYPE (x)) == METHOD_TYPE);
2954 for (; arg && arg != void_list_node; arg = TREE_CHAIN (arg), ++i)
2955 {
2956 if (TREE_PURPOSE (arg))
2957 saw_def = true;
2958 else if (saw_def)
2959 {
2960 cp_error_at ("default argument missing for parameter %P of `%+#D'",
2961 i, x);
2962 TREE_PURPOSE (arg) = error_mark_node;
2963 }
2964 }
2965 }

在FUNCTION_DECL节点中,宏TREE_TYPE给出了函数的返回类型,而TYPE_ARG_TYPES是由参数类型组成的TREE_LIST。该链表中每个节点的TREE_VALUE 是对应参数的类型,TREE_PURPOSE,如果不为空,是参数缺省值的表达式。如果链表的最后一个节点是void_list_node(一个TREE_LIST节点,其TREE_VALUE是void_type_node), 那么还是不接受可变数目参数。否则,函数接受可变数目参数。

pushdecl (continue)

753 if (DECL_NON_THUNK_FUNCTION_P(x) && !DECL_FUNCTION_MEMBER_P(x))
754 {
755 t = push_overloaded_decl (x, PUSH_LOCAL);
756 if (t != x)
757 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
758 if (!namespace_bindings_p ())
759 /* We do not need to create a binding for this name;
760 push_overloaded_decl will have already done so if
761 necessary. */
762 need_new_binding = 0;
763 }

在753行,该函数不是一个thunk或类方法。而在对push_overloaded_decl的调用中,参数flags是PUSH_LOCAL,这表示在当前作用域绑定decl,而不是非要在名字空间中。

1986 static tree
1987 push_overloaded_decl (tree decl, int flags) in name-lookup.c
1988 {
1989 tree name = DECL_NAME (decl);
1990 tree old;
1991 tree new_binding;
1992 int doing_global = (namespace_bindings_p () || !(flags & PUSH_LOCAL));
1993
1994 timevar_push (TV_NAME_LOOKUP);
1995 if (doing_global)
1996 old = namespace_binding (name, DECL_CONTEXT (decl));
1997 else
1998 old = lookup_name_current_level (name);
1999
2000 if (old)
2001 {
...
2040 }
2041
2042 if (old || TREE_CODE (decl) == TEMPLATE_DECL
2043 /* If it's a using declaration, we always need to build an OVERLOAD,
2044 because it's the only way to remember that the declaration comes
2045 from 'using', and have the lookup behave correctly. */
2046 || (flags & PUSH_USING))
2047 {
...
2054 }
2055 else
2056 /* NAME is not ambiguous. */
2057 new_binding = decl;
2058
2059 if (doing_global)
2060 set_namespace_binding (name, current_namespace, new_binding);
2061 else
2062 {
...
2099 }
2100
2101 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, decl);
2102 }

现在我们正在一个名字空间中(全局名字空间),在1992行的doing_global被设置为1,虽然flags是PUSH_LOCAL。而对于这个内建函数,这个时刻,相同的标识符不应该在这个名字空间中出现。
set_namespace_binding把作用域加入了声明所对应的标识符中,但仍未将该声明真正加入作用域,因此need_new_binding保持为1。然后,pushdecl的余下代码将这个声明加入由这个作用域维护的name链表中。

pushdecl (continue)

1009 if (need_new_binding)
1010 add_decl_to_level (x,
1011 DECL_NAMESPACE_SCOPE_P (x)
1012 ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
1013 : current_binding_level);
1014
1015 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
1016 }
4.3.1.7.5.6.4. 为内建函数创建RTX对象
与用户定义的函数不同,编译器了解内建函数的每一个细节。在随后的代码解析中,对每处内建函数的调用,编译器都会用一段中间形式的代码将其展开(这时,内建函数更像宏)。正如我们前面看到的,对于有库函数版本的内建函数,在展开代码无法应对的情况下,编译器将调用库函数,也就是构建一个call。这个call语句我们可以直接把它构建成RTL形式,那么在后面,只要把它交给后端,后端将为之产生汇编代码。

builtin_function_1 (continue)

3241 /* Since `pushdecl' relies on DECL_ASSEMBLER_NAME instead of DECL_NAME,
3242 we cannot change DECL_ASSEMBLER_NAME until we have installed this
3243 function in the namespace. */
3244 if (libname)
3245 SET_DECL_ASSEMBLER_NAME (decl, get_identifier (libname));
3246 make_decl_rtl (decl, NULL);
3247
3248 /* Warn if a function in the namespace for users
3249 is used without an occasion to consider it declared. */
3250 if (name[0] != '_' || name[1] != '_')
3251 DECL_ANTICIPATED (decl) = 1;

注意,对于库函数版本的内建函数,3244行的libname是NULL,3245行的代码将会跳过。那么,其后果就是,在下面,虽然亦为之创建SYMBOL_REF对象,但其名字为NULL,后端不会为其产生call的汇编指令。而对于__builtin版本,libname就是对应库函数的名字,在我们这个例子中是“vprintf”。

736 void
737 make_decl_rtl (tree decl, const char *asmspec) in varasm.c
738 {
739 const char *name = 0;
740 int reg_number;
741 rtx x;
742
743 /* Check that we are not being given an automatic variable. */
744 /* A weak alias has TREE_PUBLIC set but not the other bits. */
745 if (TREE_CODE (decl) == PARM_DECL
746 || TREE_CODE (decl) == RESULT_DECL
747 || (TREE_CODE (decl) == VAR_DECL
748 && !TREE_STATIC (decl)
749 && !TREE_PUBLIC (decl)
750 && !DECL_EXTERNAL (decl)
751 && !DECL_REGISTER (decl)))
752 abort ();
753 /* And that we were not given a type or a label. */
754 else if (TREE_CODE (decl) == TYPE_DECL
755 || TREE_CODE (decl) == LABEL_DECL)
756 abort ();
757
758 /* For a duplicate declaration, we can be called twice on the
759 same DECL node. Don't discard the RTL already made. */
760 if (DECL_RTL_SET_P (decl))
761 {
...
777 }
778
779 reg_number = decode_reg_name (asmspec);
780 if (reg_number == -2)
781 {
...
788 }
789
790 name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
791
792 if (TREE_CODE (decl) != FUNCTION_DECL && DECL_REGISTER (decl))
793 {
...
842 }
...
862 x = gen_rtx_SYMBOL_REF (Pmode, name);
863 SYMBOL_REF_WEAK (x) = DECL_WEAK (decl);
864 SYMBOL_REF_DECL (x) = decl;
865
866 x = gen_rtx_MEM (DECL_MODE (decl), x);
867 if (TREE_CODE (decl) != FUNCTION_DECL)
868 set_mem_attributes (x, decl, 1);
869 SET_DECL_RTL (decl, x);
870
871 /* Optionally set flags or add text to the name to record information
872 such as that it is a function name.
873 If the name is changed, the macro ASM_OUTPUT_LABELREF
874 will have to know how to strip this information. */
875 (* targetm.encode_section_info) (decl, DECL_RTL (decl), true);
876 }

在make_decl_rtx中,参数asmspec,如果非0,是用户指定的汇编符号名。在asmspec为NULL的情况下,在779行,decode_reg_name不作任何事情,仅返回-1。然后在790行, DECL_ASSEMBLER_NAME访问声明节点的assembler_name域(在上面3245设置的),这是将要给汇编器看的标识符,name则指向其名字(在C++中,交给汇编器的都是经过修饰的名字)。接着在862行,为这个名字创建了一个引用(SYMBOL_REF),866行则是建立其内存描述对象(MEM)。



图 38:__builtin_vprintf的RTX对象

目标平台相关的函数encode_section_info确定声明的属性,然后编译器可以决定所需的段(sections)及在那个段中安放这个声明。

5154 void
5155 default_encode_section_info(tree decl, rtx rtl, int first ATTRIBUTE_UNUSED) in varasm.c
5156 {
5157 rtx symbol;
5158 int flags;
5159
5160 /* Careful not to prod global register variables. */
5161 if (GET_CODE (rtl) != MEM)
5162 return;
5163 symbol = XEXP (rtl, 0);
5164 if (GET_CODE (symbol) != SYMBOL_REF)
5165 return;
5166
5167 flags = 0;
5168 if (TREE_CODE (decl) == FUNCTION_DECL)
5169 flags |= SYMBOL_FLAG_FUNCTION;
5170 if ((*targetm.binds_local_p) (decl))
5171 flags |= SYMBOL_FLAG_LOCAL;
5172 if ((*targetm.in_small_data_p) (decl))
5173 flags |= SYMBOL_FLAG_SMALL;
5174 if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
5175 flags |= decl_tls_model (decl) << SYMBOL_FLAG_TLS_SHIFT;
5176 /* ??? Why is DECL_EXTERNAL ever set for non-PUBLIC names? Without
5177 being PUBLIC, the thing *must* be defined in this translation unit.
5178 Prevent this buglet from being propagated into rtl code as well. */
5179 if (DECL_P (decl) && DECL_EXTERNAL (decl) && TREE_PUBLIC (decl))
5180 flags |= SYMBOL_FLAG_EXTERNAL;
5181
5182 SYMBOL_REF_FLAGS (symbol) = flags;
5183 }

在上面的函数中,binds_local_p不是真正地依赖于目标平台。事实上,一个符号是否是局部的取决于语言的特性而不是平台。

5197 bool
5198 default_binds_local_p (tree exp) in varasm.c
5199 {
5200 return default_binds_local_p_1 (exp, flag_shlib);
5201 }

注意下面函数中条件的次序。在5215行,如果一个符号的可见性不是VISIBILITY_DEFAULT,它必为VISIBILITY_INTERNAL,或VISIBILITY_HIDDEN,或VISIBILITY_PROTECTED(由visibility属性设置,默认值为VISIBILITY_DEFAULT)。

5203 bool
5204 default_binds_local_p_1 (tree exp, int shlib) in varasm.c
5205 {
5206 bool local_p;
5207
5208 /* A non-decl is an entry in the constant pool. */
5209 if (!DECL_P (exp))
5210 local_p = true;
5211 /* Static variables are always local. */
5212 else if (! TREE_PUBLIC (exp))
5213 local_p = true;
5214 /* A variable is local if the user tells us so. */
5215 else if (DECL_VISIBILITY (exp) != VISIBILITY_DEFAULT)
5216 local_p = true;
5217 /* Otherwise, variables defined outside this object may not be local. */
5218 else if (DECL_EXTERNAL (exp))
5219 local_p = false;
5220 /* Linkonce and weak data are never local. */
5221 else if (DECL_ONE_ONLY (exp) || DECL_WEAK (exp))
5222 local_p = false;
5223 /* If PIC, then assume that any global name can be overridden by
5224 symbols resolved from other modules. */
5225 else if (shlib)
5226 local_p = false;
5227 /* Uninitialized COMMON variable may be unified with symbols
5228 resolved from other modules. */
5229 else if (DECL_COMMON (exp)
5230 && (DECL_INITIAL (exp) == NULL
5231 || DECL_INITIAL (exp) == error_mark_node))
5232 local_p = false;
5233 /* Otherwise we're left with initialized (or non-common) global data
5234 which is of necessity defined locally. */
5235 else
5236 local_p = true;
5237
5238 return local_p;
5239 }

在default_encode_section_info的5172行,钩子in_small_data_p返回true,如果decl可以被放进一个“小数据”段("small data" section)。对于x86机器,它是返回false的默认函数。某些RISC机器需要定义这个函数,例如MIPS,它的指令长度固定,取址方式有限。在一条指令中,从某一地址,通过偏移量访问的内存范围局限。对于分布太广的地址,每次访问都需要2条指令。告知这个情况,可以使编译器产生更高效的代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: