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

来源:互联网 发布:java中md5加密设置位数 编辑:程序博客网 时间:2024/05/17 09:27
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个独立的函数。例如,对于strcmp2个内建函数,__builtin_strcmpstrcmp本身。2个函数的行为是相同的。其他内建函数则仅定义了__builtin 变体。如果BOTH_P TRUE,那么这个内建函数就有2个变体;否则它只有第一个变体。

TYPE表示函数的类型。这个符号对应于来自builtin-types.def的枚举值。如果BOTH_Ptrue,那么LIBTYPE就是非__builtin_变体的类型。否则,LIBTYPE将被忽略。

如果FALLBACK_Ptrue那么,如果出于某些原因,编译器不能直接展开这个内建函数,它将调用对应的库函数(不带__builtin_前缀的那个)。

如果NONANSI_Ptrue,那么非__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节点

内建函数vprintfBOTH_Ptrue,表明它有2个变体,一个是builtin,另一个是库函数(严格的说,是库函数vprintf的中间形式的声明,它链接到库函数vprintf)。这个内建函数需要builtin_function_2来创建它的2个变体。另外,vprintfIMPLICITtrue,产生出来的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_BUILTINDEF_LIB_BUILTINDEF_C99_BUILTINDEF_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]

注意contextNULL——这个声明是在全局名字空间中。

 

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_codeERROR_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_VALUEvoid_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的调用中,参数flagsPUSH_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,虽然flagsPUSH_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行的libnameNULL3245行的代码将会跳过。那么,其后果就是,在下面,虽然亦为之创建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,是用户指定的汇编符号名。在asmspecNULL的情况下,在779行,decode_reg_name不作任何事情,仅返回-1。然后在790行, DECL_ASSEMBLER_NAME访问声明节点的assembler_name域(在上面3245设置的),这是将要给汇编器看的标识符,name则指向其名字(在C++中,交给汇编器的都是经过修饰的名字)。接着在862行,为这个名字创建了一个引用(SYMBOL_REF),866行则是建立其内存描述对象(MEM)。

38__builtin_vprintfRTX对象

目标平台相关的函数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_info5172行,钩子in_small_data_p返回true,如果decl可以被放进一个“小数据”段("small data" section)。对于x86机器,它是返回false的默认函数。某些RISC机器需要定义这个函数,例如MIPS,它的指令长度固定,取址方式有限。在一条指令中,从某一地址,通过偏移量访问的内存范围局限。对于分布太广的地址,每次访问都需要2条指令。告知这个情况,可以使编译器产生更高效的代码。

 

 

原创粉丝点击