Studying note of GCC-3.4.6 source (67)

4.3.1.7.8.3.      Exception handler

Next, if we don’t prohibit exception via switch -fno-exception, C++ runtime will setup the functions’ declaration excepted by exception handling. In C++, if throw an exception but not catch it, then in global namespace, the runtime would catch it and call std::terminate() to terminate the program. This funcationality is provided by the runtime function__cxa_call_unexpected defined in “gcc-3.4.6/libstdc++-v3/libstdsupc++/eh_personality.cc”.

In parsing throw and catch statement, the compiler would setup the context carried by the exception object, and invokes exception handling logic with the context, __cxa_call_unexpected, __gxx_personality_v0 or __gxx_personality_sj0 are all handlers refered by the context. The exception handling logic and the setup of the context is very complex, we don’t plan to go deep into it. After finishing the follow-up sections about parsing and hanlding complex types, code of this part isn’t very hard for understanding.

 

60      void

61      init_exception_processing (void)                                                                      in expt.c

62      {

63        tree tmp;

64     

65        /* void std::terminate (); */

66        push_namespace (std_identifier);

67        tmp = build_function_type (void_type_node, void_list_node);

68        terminate_node = build_cp_library_fn_ptr ("terminate", tmp);

69        TREE_THIS_VOLATILE (terminate_node) = 1;

70        TREE_NOTHROW (terminate_node) = 1;

71        pop_namespace ();

72     

73        /* void __cxa_call_unexpected(void *); */

74        tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);

75        tmp = build_function_type (void_type_node, tmp);

76        call_unexpected_node

77          = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp);

78     

79        eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS

80                                            ? "__gxx_personality_sj0"

81                                            : "__gxx_personality_v0");

82     

83        lang_eh_runtime_type = build_eh_type_type;

84        lang_protect_cleanup_actions = &cp_protect_cleanup_actions;

85      }

 

As std::terminate is a library routine, its declaration is built by build_cp_library_fn_ptr. Remember that build_cp_library_fn will find out (create if not find) the identifer node for mangled version for the declaration and set it as the assemble name for the declaration node. Then at linking stage, linker will find the function by this assemble name in the space of library.

 

3350   tree

3351   build_cp_library_fn_ptr (const char* name, tree type)                                        in decl.c

3352   {

3353     return build_cp_library_fn (get_identifier (name), ERROR_MARK, type);

3354   }

 

Routine __cxa_call_unexpected is declared as extern “C”, which means a C version function declaration. Its name will not undergo mangling.

 

3393   tree

3394   push_throw_library_fn (tree name, tree type)                                                    in decl.c

3395   {

3396     tree fn = push_library_fn (name, type);

3397     TREE_THIS_VOLATILE (fn) = 1;

3398     TREE_NOTHROW (fn) = 0;

3399     return fn;

3400   }

 

Notice that in build_library_fn, the language for the declaration is set as C, and no assemble name is set as its name can’t be mangled under C.

 

3359   tree

3360   push_library_fn (tree name, tree type)                                                              in decl.c

3361   {

3362     tree fn = build_library_fn (name, type);

3363     pushdecl_top_level (fn);

3364     return fn;

3365   }

 

Now pushdecl_top_level will push this declaration into namespace of global.

 

3414   tree

3415   pushdecl_top_level (tree x)                                                               in name-lookup.c

3416   {

3417     return pushdecl_top_level_1 (x, NULL);

3418   }

 

Below push_to_top_level caches identifiers from current bindng scope to global namespace and it will leave us at global namespace. And pop_from_top_level would restore current scope.

 

3400   static tree

3401   pushdecl_top_level_1 (tree x, tree *init)                                             in name-lookup.c

3402   {

3403     timevar_push (TV_NAME_LOOKUP);

3404     push_to_top_level ();

3405     x = pushdecl_namespace_level (x);

3406     if (init)

3407       cp_finish_decl (x, *init, NULL_TREE, 0);

3408     pop_from_top_level ();

3409     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

3410   }

 

Though it tries to push the entity into current namespace, it is possible that we are also within a binding scope within current namespace (of course, for our case here we just in global namespace, but from view of pushdecl_namespace_level, it is possible). Below at line 3232 current binding scope (current namespace or may not) is fetched.

 

3229   tree

3230   pushdecl_namespace_level (tree x)                                                     in name-lookup.c

3231   {

3232     struct cp_binding_level *b = current_binding_level;

3233     tree t;

3234  

3235     timevar_push (TV_NAME_LOOKUP);

3236     t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));

 

For push entity within namespace, pushdecl_with_scope acts like pushdecl except it works for specified namespace instead of current ones, so caching current binding scope and restoring after that is required.

 

1941   tree

1942   pushdecl_with_scope (tree x, cxx_scope *level)                                   in name-lookup.c

1943   {

1944     struct cp_binding_level *b;

1945     tree function_decl = current_function_decl;

1946  

1947     timevar_push (TV_NAME_LOOKUP);

1948     current_function_decl = NULL_TREE;

1949     if (level->kind == sk_class)

1950     {

1951       b = class_binding_level;

1952       class_binding_level = level;

1953       pushdecl_class_level (x);

1954       class_binding_level = b;

1955     }

1956     else

1957     {

1958       b = current_binding_level;

1959       current_binding_level = level;

1960       x = pushdecl (x);

1961       current_binding_level = b;

1962     }

1963     current_function_decl = function_decl;

1964     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1965   }

 

For each binding scope, if it is a class scope, field class_shadowed records types bound in. While field type_shadowed is not confined to class scope, but in all non-namespace scopes to record types being shadowed (if no shadowed type, it is itself). Why is non-namespace scope? Because via field level_chain, it is easily to determine whether specified identifier is visible at specified namespace due to they are always the outer-most scopes and effective.

 

pushdecl_namespace_level (continue)

 

3238     /* Now, the type_shadowed stack may screw us. Munge it so it does

3239       what we want.  */

3240     if (TREE_CODE (x) == TYPE_DECL)

3241     {

3242       tree name = DECL_NAME (x);

3243       tree newval;

3244       tree *ptr = (tree *)0;

3245       for (; !global_scope_p (b); b = b->level_chain)

3246       {

3247         tree shadowed = b->type_shadowed;

3248         for (; shadowed; shadowed = TREE_CHAIN (shadowed))

3249           if (TREE_PURPOSE (shadowed) == name)

3250           {

3251             ptr = &TREE_VALUE (shadowed);

3252             /* Can't break out of the loop here because sometimes

3253               a binding level will have duplicate bindings for

3254               PT names. It's gross, but I haven't time to fix it.  */

3255           }

3256       }

3257       newval = TREE_TYPE (x);

3258       if (ptr == (tree *)0)

3259       {

3260         /* @@ This shouldn't be needed. My test case "zstring.cc" trips

3261           up here if this is changed to an assertion.  --KR  */

3262         SET_IDENTIFIER_TYPE_VALUE (name, x);

3263       }

3264       else

3265       {

3266         *ptr = newval;

3267       }

3268     }

3269     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);

3270   }

 

As we have mentioned above, current binding scope may be in current namespace. Now we have added new type into current namespace, then it needs to check if between current scope and current namespace, this type would be shadowed. At line 3245, b is the current scope, via level_chain, it can climb up to global namespace, but because type_shadowed is not used by namespace, so the entity found by FOR loop at line 3245, is the type shadowed by inner scope closest to current namespace, which is declared in outside namespace (the usage of the function promises this). No doubt, the type shadowed should be updated as currently adding type (line 3262). If these inner scopes haven’t type declaration of the name, ptr would be 0 (line 3258).

Both __gxx_personality_sj0 and __gxx_personality_v0 are declared with C signature (extern “C”). Their declaration is generated by init_one_libfunc, which likes: int __gxx_personality_sj0().

 

5126   rtx

5127   init_one_libfunc (const char *name)                                                          in optabs.c

5128   {

5129     rtx symbol;

5130  

5131     /* Create a FUNCTION_DECL that can be passed to

5132       targetm.encode_section_info.  */

5133     /* ??? We don't have any type information except for this is

5134       a function. Pretend this is "int foo()".  */

5135     tree decl = build_decl (FUNCTION_DECL, get_identifier (name),

5136                        build_function_type (integer_type_node, NULL_TREE));

5137     DECL_ARTIFICIAL (decl) = 1;

5138     DECL_EXTERNAL (decl) = 1;

5139     TREE_PUBLIC (decl) = 1;

5140  

5141     symbol = XEXP (DECL_RTL (decl), 0);

5142  

5143     /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with

5144       are the flags assigned by targetm.encode_section_info.  */

5145     SYMBOL_REF_DECL (symbol) = 0;

5146  

5147     return symbol;

5148   }

 

At line 5141, DECL_RTL will invoke make_decl_rtl (to get detail, refer to Create RTX object for builtin). Notice that in that function at line 790, it will fetch the mangled name of the declaration, but we haven’t the correct function signature in hand now (compared with that in unwind-cxx.h)!

Fortunately, here we don’t need fully correct signature of the function to get the entry name in the library. Routines like __gxx_personality_v0 here generated by language-independent part has C linkage. That is the mangled names are the same of their declared name. As long as we provide correct arguments at run-time, everything is OK.

4.3.1.7.8.4.      Detect behavor of linker and other

GCC supports concept of weak symbol.

Having two or more global symbols of the same name will not cause a conflict as long as all but one of them are declared as being weak symbols. The linker ignores the definitions of the weak symbols and uses the normal global symbol definition to resolve all references, but the weak symbols will be used if the normal global symbol is not available. A weak symbol can be used to name functions and data that can be overridden by user code. A weak symbol is also referred to as a weak alias, or simply weak.

Besides, GCC can also output following assembler directive.

linkonce[type]: Marks the current section so it is included by the linker only once, even if the same section appears in multiple modules. The directive must appear once in each instance of the section. The section is selected only by name, so the name must be unique.

The optional type argument can be discard to have duplicates silently discarded (the default). A type of one_only will issue a warning for each duplicate found. A type of same_size will issue a warning if any of the duplicates are not the same size. A type of same_contents will issue a warning if any of the duplicates do not contain exactly the same data.

These are all target dependent. For x86, elf format output, support_one_only returns 0 and sets flag_weak as 0.

 

4549   int

4550   supports_one_only (void)                                                                         in varasm.c

4551   {

4552     if (SUPPORTS_ONE_ONLY)

4553       return 1;

4554     return SUPPORTS_WEAK;

4555   }

 

In coding, we can use __func__, __FUNCTION__, __PRETTY__FUNCTION__ to fetch current function name. Function pointer make_fname_decl saves the processing function, which at line 3129, is set by cp_make_fname_decl. Function start_fname_decls then prepares the stack for saving these functions’ name. Later we will see this funciton again.

4.3.1.8.    Setup preprocessor

Returns from cxx_init_decl_processing, the front-end has C++ runtime setup, it comes to setup preprocessor. First it creates the familiar “null” object, which as we have seen in our program, in fact is an integer of 0. However, note that it has size of a pointer.

 

cxx_init (continue)

 

412   /* Create the built-in __null node.  */

413    null_node = build_int_2 (0, 0);

414    TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);

415    ridpointers[RID_NULL] = null_node;

416 

417    interface_unknown = 1;

418 

419    if (c_common_init () == false)

420    {

421      pop_srcloc();

422      return false;

423    }

 

Below cpp_init_iconv initializes iconv descriptors for conversion from the source character set to the execution character sets. We ignore this part. And flag_preprocess_only if nonzero, means only to do preprocessing, which is ready here, and invokes preprocess_file at line 1207. And we will return here to finish the file’s compilation.

 

1186   bool

1187   c_common_init (void)                                                                              in c-opts.c

1188   {

1189     input_line = saved_lineno;

1190  

1191     /* Set up preprocessor arithmetic. Must be done after call to

1192       c_common_nodes_and_builtins for type nodes to be good.  */

1193     cpp_opts->precision = TYPE_PRECISION (intmax_type_node);

1194     cpp_opts->char_precision = TYPE_PRECISION (char_type_node);

1195     cpp_opts->int_precision = TYPE_PRECISION (integer_type_node);

1196     cpp_opts->wchar_precision = TYPE_PRECISION (wchar_type_node);

1197     cpp_opts->unsigned_wchar = TREE_UNSIGNED (wchar_type_node);

1198     cpp_opts->bytes_big_endian = BYTES_BIG_ENDIAN;

1199  

1200     /* This can't happen until after wchar_precision and bytes_big_endian

1201       are known.  */

1202     cpp_init_iconv (parse_in);

1203  

1204     if (flag_preprocess_only)

1205     {

1206       finish_options ();

1207       preprocess_file (parse_in);

1208       return false;

1209     }

1210  

1211    /* Has to wait until now so that cpplib has its hash table.  */

1212     init_pragma ();

1213  

1214     return true;

1215   }

 

And if full compilation is expected, then for x86 linux, here only two directives “pack”, and “weak” are available for C (they will appear in __attribute__() block), as #pragma directive is architecture dependent.

 

494    void

495    init_pragma (void)                                                                           in c-pragma.c

496    {

497    #ifdef HANDLE_PRAGMA_PACK

498      c_register_pragma (0, "pack", handle_pragma_pack);

499    #endif

500    #ifdef HANDLE_PRAGMA_WEAK

501      c_register_pragma (0, "weak", handle_pragma_weak);

502    #endif

503    #ifdef HANDLE_PRAGMA_REDEFINE_EXTNAME

504      c_register_pragma (0, "redefine_extname", handle_pragma_redefine_extname);

505    #endif

506    #ifdef HANDLE_PRAGMA_EXTERN_PREFIX

507      c_register_pragma (0, "extern_prefix", handle_pragma_extern_prefix);

508    #endif

509   

510    #ifdef REGISTER_TARGET_PRAGMAS

511       REGISTER_TARGET_PRAGMAS ();

512    #endif

513    }

 

c_register_pragma inserts identifier of directives into hashtable of ident_hash and binds them with their handler.

 

486    void

487    c_register_pragma (const char *space, const char *name,                      in c-pragma.c

488                   void (*handler) (struct cpp_reader *))

489    {

490      cpp_register_pragma (parse_in, space, name, handler);

491    }

4.3.1.9.    Finish front-end initialization

C++ supports more #pragma directives, so initializes them in below.

 

cxx_init (continue)

 

425    init_cp_pragma ();

426 

427    init_repo (main_input_filename);

428 

429    pop_srcloc();

430    return true;

431  }

 

Below #pragma vtable is no longer supported, and #pragma unit, gcc doesn’t implement it yet.

 

368    static void

369    init_cp_pragma (void)                                                                                    in lex.c

370    {

371      c_register_pragma (0, "vtable", handle_pragma_vtable);

372      c_register_pragma (0, "unit", handle_pragma_unit);

373      c_register_pragma (0, "interface", handle_pragma_interface);

374      c_register_pragma (0, "implementation", handle_pragma_implementation);

375      c_register_pragma ("GCC", "interface", handle_pragma_interface);

376      c_register_pragma ("GCC", "implementation", handle_pragma_implementation);

377      c_register_pragma ("GCC", "java_exceptions", handle_pragma_java_exceptions);

378    }

 

When compiles the code using the -frepo option, it causes the creation of files with the suffix .rpo, each listing the template instantiations to be found in its corresponding object file. The link wrapper utility, named collect2, will then be invoked to update the .rpo files with instructions to the linker as to the placement of the template instances in the final program. The only difficulty with this approach has to do with librariesunless the associated .rpo files are also present, linking template instantiations stored in a library will fail.

At line 427, init_repo creates .rpo version file for main input file.

 

你可能感兴趣的:(Studying note of GCC-3.4.6 source (67))