From 8a14b0eb312628ad9cce8ac9f439c420b12b33c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Mon, 4 Oct 2021 09:24:43 +0200 Subject: [PATCH] gcc: implement AIX-style constructors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AIX linker now supports constructors and destructors detection. For such functions to be detected, their name must starts with __sinit or __sterm. and -bcdtors must be passed to linker calls. It will create "_cdtors" symbol which can be used to launch the initialization. This patch creates a new RS6000 flag "-mcdtors=". With "-mcdtors=aix", gcc will generate these new constructors/destructors. With "-mcdtors=gcc", which is currently the default, gcc will continue to generate "gcc" format for constructors (ie _GLOBAL__I and _GLOBAL__D symbols). Ideally, it would have been better to enable the AIX format by default instead of using collect2. However, the compatibility between the previously-built binaries and the new ones is too complex to be done. gcc/ChangeLog: 2021-10-04 Clément Chigot * collect2.c (aixbcdtors_flags): New variable. (main): Use it to detect -bcdtors and remove -binitfini flag. (write_c_file_stat): Adapt to new AIX format. * config/rs6000/aix.h (FILE_SINIT_FORMAT): New define. (FILE_STERM_FORMAT): New define. (TARGET_FILE_FUNCTION_FORMAT): New define. * config/rs6000/aix64.opt: Add -mcdtors flag. * config/rs6000/aix71.h (LINK_SPEC_COMMON): Pass -bcdtors when -mcdtors=aix is passed. (STARTFILE_SPEC): Add crtcdtors.o with -mcdtors=aix. * config/rs6000/aix72.h (LINK_SPEC_COMMON): Likewise. (STARTFILE_SPEC): Likewise. * config/rs6000/aix73.h (LINK_SPEC_COMMON): Likewise. (STARTFILE_SPEC): Likewise. * config/rs6000/rs6000-opts.h (enum rs6000_cdtors): New enum. * doc/invoke.texi: Add -mcdtors flag. * tree.c (get_file_function_name): Add TARGET_FILE_FUNCTION_FORMAT support. libgcc/ChangeLog: * config.host: Add crtcdtors.o files. * config/rs6000/t-aix-cxa: Likewise. * config/rs6000/crtcdtors.c: New file. gcc/testsuite/ChangeLog: 2021-10-04 Clément Chigot * gcc.target/powerpc/constructor-aix.c: New test. --- gcc/collect2.c | 63 ++++++++++++++++--- gcc/config/rs6000/aix.h | 56 +++++++++++++++++ gcc/config/rs6000/aix64.opt | 17 +++++ gcc/config/rs6000/aix71.h | 10 ++- gcc/config/rs6000/aix72.h | 10 ++- gcc/config/rs6000/aix73.h | 10 ++- gcc/config/rs6000/rs6000-opts.h | 8 +++ gcc/doc/invoke.texi | 21 ++++++- .../gcc.target/powerpc/constructor-aix.c | 12 ++++ gcc/tree.c | 5 ++ libgcc/config.host | 2 +- libgcc/config/rs6000/crtcdtors.c | 53 ++++++++++++++++ libgcc/config/rs6000/t-aix-cxa | 12 ++++ 13 files changed, 260 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.target/powerpc/constructor-aix.c create mode 100644 libgcc/config/rs6000/crtcdtors.c diff --git a/gcc/collect2.c b/gcc/collect2.c index 33114322f01..3d04bc8465f 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -186,6 +186,7 @@ static int aix64_flag; /* true if -b64 */ static int aixrtl_flag; /* true if -brtl */ static int aixlazy_flag; /* true if -blazy */ static int visibility_flag; /* true if -fvisibility */ +static int aixbcdtors_flag; /* True if -bcdtors */ #endif enum lto_mode_d { @@ -984,6 +985,8 @@ main (int argc, char **argv) aixrtl_flag = 0; else if (strcmp (argv[i], "-blazy") == 0) aixlazy_flag = 1; + else if (strcmp (argv[i], "-bcdtors") == 0) + aixbcdtors_flag = 1; #endif } @@ -1731,7 +1734,9 @@ main (int argc, char **argv) /* Tell the linker that we have initializer and finalizer functions. */ #ifdef LD_INIT_SWITCH #ifdef COLLECT_EXPORT_LIST - *ld2++ = concat (LD_INIT_SWITCH, ":", initname, ":", fininame, NULL); + /* Do not emit -binitfini when -bcdtors is enabled. */ + if (!aixbcdtors_flag) + *ld2++ = concat (LD_INIT_SWITCH, ":", initname, ":", fininame, NULL); #else *ld2++ = LD_INIT_SWITCH; *ld2++ = initname; @@ -2020,6 +2025,7 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) { const char *p, *q; char *prefix, *r; + char *regframe_name, *deregframe_name; int frames = (frame_tables.number > 0); /* Figure out name of output_file, stripping off .so version. */ @@ -2062,6 +2068,22 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) aix_shared_fininame = concat ("_GLOBAL__AIXD_", prefix, NULL); #endif + regframe_name = concat ("reg_frame", NULL, NULL); + deregframe_name = concat ("dereg_frame", NULL, NULL); +#ifdef COLLECT_EXPORT_LIST + /* In order to be detected by the linker, sinit/sterm symbols + must be external. Thus, reg_frame and dereg_frame can't + be static anymore and their name needs to be unique. + In order to ensure that frames are initialized before any + constructors, their constructor must have the highest priority + 0. */ + if (aixbcdtors_flag) + { + regframe_name = concat ("__sinit0_reg_frame_", prefix, NULL); + deregframe_name = concat ("__sterm0_dereg_frame_", prefix, NULL); + } +#endif + free (prefix); /* Write the tables as C code. */ @@ -2073,9 +2095,16 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) mechanisms GCC uses to order constructors across different dependent shared libraries (see config/rs6000/aix.h). */ - fprintf (stream, "static int count;\n"); - fprintf (stream, "typedef void entry_pt();\n"); - write_list_with_asm (stream, "extern entry_pt ", constructors.first); +#ifdef COLLECT_EXPORT_LIST + if (!aixbcdtors_flag) + { +#endif + fprintf (stream, "static int count;\n"); + fprintf (stream, "typedef void entry_pt();\n"); + write_list_with_asm (stream, "extern entry_pt ", constructors.first); +#ifdef COLLECT_EXPORT_LIST + } +#endif if (frames) { @@ -2102,7 +2131,12 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) fprintf (stream, "extern void *__gcc_unwind_dbase;\n"); #endif - fprintf (stream, "static void reg_frame () {\n"); +#ifdef COLLECT_EXPORT_LIST + if (aixbcdtors_flag) + fprintf (stream, "void %s () {\n", regframe_name); + else +#endif + fprintf (stream, "static void %s () {\n", regframe_name); fprintf (stream, "\tstatic struct object ob;\n"); #ifdef TARGET_AIX_VERSION /* Use __gcc_unwind_dbase as the base address for data on AIX. @@ -2114,11 +2148,24 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) #endif fprintf (stream, "\t}\n"); - fprintf (stream, "static void dereg_frame () {\n"); +#ifdef COLLECT_EXPORT_LIST + if (aixbcdtors_flag) + fprintf (stream, "void %s () {\n", deregframe_name); + else +#endif + fprintf (stream, "static void %s () {\n", deregframe_name); fprintf (stream, "\t__deregister_frame_info (frame_table);\n"); fprintf (stream, "\t}\n"); } +#ifdef COLLECT_EXPORT_LIST + /* Files built with the new AIX cdtors format don't need to + explicitly call them. + NOTE: This breaks compatibility with previously-built files. */ + if (aixbcdtors_flag) + return; +#endif + #ifdef COLLECT_EXPORT_LIST /* Set visibility of initializers to default. */ if (visibility_flag) @@ -2130,7 +2177,7 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) fprintf (stream, "\tstatic entry_pt *ctors[] = {\n"); write_list (stream, "\t\t", constructors.first); if (frames) - fprintf (stream, "\treg_frame,\n"); + fprintf (stream, "\t%s,\n", regframe_name); fprintf (stream, "\t};\n"); fprintf (stream, "\tentry_pt **p;\n"); fprintf (stream, "\tif (count++ != 0) return;\n"); @@ -2147,7 +2194,7 @@ write_c_file_stat (FILE *stream, const char *name ATTRIBUTE_UNUSED) fprintf (stream, "\tstatic entry_pt *dtors[] = {\n"); write_list (stream, "\t\t", destructors.first); if (frames) - fprintf (stream, "\tdereg_frame,\n"); + fprintf (stream, "\t%s,\n", deregframe_name); fprintf (stream, "\t};\n"); fprintf (stream, "\tentry_pt **p;\n"); fprintf (stream, "\tif (--count != 0) return;\n"); diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h index 0f4d8cb2dc8..d9ed88cb459 100644 --- a/gcc/config/rs6000/aix.h +++ b/gcc/config/rs6000/aix.h @@ -284,3 +284,59 @@ #define SUBTARGET_DRIVER_SELF_SPECS \ "%{m64:-maix64} %. */ + +#ifndef SHARED +extern void (* _cdtors[]) (void); +extern void __run_initial_ctors (void (**) (void)); +extern void __run_final_dtors (void); + +void _AIX_init(void); +void _AIX_init(void) +{ + /* Run CTORs now */ + __run_initial_ctors(&_cdtors[0]); + + /* Warn exit() that we want to run dtors at the end */ + __run_final_dtors(); +} + +void (*__C_runtime_pstartup) (void) = _AIX_init; + +#endif + +/* crtcxa is compiled without -mcdtors=aix flag. Thus, a new + destructor must be created following AIX format and this file + must be compiled with -mcdtors=aix to enable it. */ +void __init_aix_libgcc_cxa_atexit_dup (void) __attribute__ ((destructor (65535))); +void __init_aix_libgcc_cxa_atexit_dup (void) +{ + __init_aix_libgcc_cxa_atexit (); +} diff --git a/libgcc/config/rs6000/t-aix-cxa b/libgcc/config/rs6000/t-aix-cxa index 0e1bccb1525..e9e862909bc 100644 --- a/libgcc/config/rs6000/t-aix-cxa +++ b/libgcc/config/rs6000/t-aix-cxa @@ -24,3 +24,15 @@ crtcxa_64.o: $(srcdir)/config/rs6000/crtcxa.c crtcxa_64_s.o: $(srcdir)/config/rs6000/crtcxa.c $(crt_compile) -maix64 -DSHARED -c $< + +crtcdtors.o: $(srcdir)/config/rs6000/crtcdtors.c + $(crt_compile) -maix32 -c $< -mcdtors=aix + +crtcdtors_s.o: $(srcdir)/config/rs6000/crtcdtors.c + $(crt_compile) -maix32 -DSHARED -c $< -mcdtors=aix + +crtcdtors_64.o: $(srcdir)/config/rs6000/crtcdtors.c + $(crt_compile) -maix64 -c $< -mcdtors=aix + +crtcdtors_64_s.o: $(srcdir)/config/rs6000/crtcdtors.c + $(crt_compile) -maix64 -DSHARED -c $< -mcdtors=aix \ No newline at end of file -- 2.33.0