Subversion Repositories QNX 8.QNX8 linker driver

Rev

Rev 10 | Rev 12 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // QNX 8.0 'gcc' linker driver drop-in replacement by Pierre-Marie Baty <pm@pmbaty.com>
  2.  
  3. // RATIONALE
  4. // until a proper QNXToolchain class is implemented in the Clang driver, Clang relies on GNU GCC to drive the system linker 'ld'.
  5. // So we *HAVE* to provide a 'gcc' executable for Clang to be able to link QNX files.
  6. // GNU GCC is itself a driver which can also invoke a compiler or a linker (gcc invokes collect2 which in turn invokes ld).
  7. // This means our GCC will need to either chain-call 'clang' when it is called for *compiling* and chain-call 'ld' when it is called for *linking*.
  8. // When proper support is added to it, GNU GCC contains a linker specification for the system which it uses to construct the linker command line.
  9. // The linker specifications for QNX 8.0 can be extracted from '<target triple>-gcc -dumpspecs' and have been reimplemented in this file.
  10. // The GNU specs language is documented here: https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html
  11.  
  12. // environment variables:
  13. //   DEBUG_LINKER_DRIVER - when defined to any value (incl. empty string), print the constructed command line to stderr before calling the linker.
  14.  
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <stdint.h>
  18. #include <stdarg.h>
  19. #include <stdbool.h>
  20. #include <string.h>
  21. #include <fcntl.h>
  22. #ifndef _WIN32
  23. #include <unistd.h>
  24. #else // _WIN32
  25. #include <process.h>
  26. #include <io.h>
  27. #define strdup(s) _strdup ((s))
  28. #define strcasecmp(a,b) _stricmp ((a), (b))
  29. #define access(f,m) _access ((f), (m))
  30. #define execvpe(exename,argv,envp) exit ((int) _spawnvpe (P_WAIT, (exename), (argv), (envp)))
  31. int vasprintf (char **out_string, const char *fmt, va_list va_args) // vasprintf() implementation
  32. {
  33.    int retval; va_list ap;
  34.    *out_string = (char *) malloc (16); if (*out_string == NULL) return (-1);
  35.    va_copy (ap, va_args); retval = vsnprintf (*out_string, 16, fmt, ap); va_end (ap); if (retval == -1) return (-1);
  36.    if (retval >= 16)
  37.    {
  38.       void *new_string = realloc (*out_string, (size_t) retval + 1); if (new_string == NULL) return (-1); *out_string = (char *) new_string;
  39.       va_copy (ap, va_args); retval = vsnprintf (*out_string, (size_t) retval + 1, fmt, va_args); va_end (ap);
  40.    }
  41.    return (retval);
  42. }
  43. int asprintf (char **out_string, const char *fmt, ...) { int retval; va_list ap; va_start (ap, fmt); retval = vasprintf (out_string, fmt, ap); va_end (ap); return (retval); } // asprintf() implementation
  44. #endif // !_WIN32
  45.  
  46.  
  47. #define BASEVER "12.2.0"
  48. #if (defined(__x86_64__) || defined(_WIN64))
  49. #define IS_TARGET_INTEL 1
  50. #define TARGET_TRIPLE "x86_64-pc-nto-qnx8.0.0"
  51. #elif defined(__aarch64__)
  52. #define IS_TARGET_INTEL 0
  53. #define TARGET_TRIPLE "aarch64-unknown-nto-qnx8.0.0"
  54. #else
  55. #error unsupported platform (not x86_64, not aarch64le). Please implement!
  56. #endif
  57. #define COMPILER "clang"
  58. #define LINKER TARGET_TRIPLE "-ld"
  59. //#define LINKER "ld.lld"
  60.  
  61.  
  62. #define ARGMODE_SINGLE   0
  63. #define ARGMODE_HASVAL   1
  64. #define ARGMODE_EQUALVAL 2
  65.  
  66.  
  67. // handy macros that generate a version number in the format "YYYYMMDD" corresponding to the build date. Usage: printf ("version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD);
  68. #ifndef VERSION_ARG_YYYYMMDD
  69. #define BUILDDATE_YEAR  (&__DATE__[7]) // compiler will optimize this into a const string, e.g. "2021"
  70. #define BUILDDATE_MONTH ( \
  71.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jan ") ? "01" : \
  72.    *((uint32_t *) __DATE__) == *((uint32_t *) "Feb ") ? "02" : \
  73.    *((uint32_t *) __DATE__) == *((uint32_t *) "Mar ") ? "03" : \
  74.    *((uint32_t *) __DATE__) == *((uint32_t *) "Apr ") ? "04" : \
  75.    *((uint32_t *) __DATE__) == *((uint32_t *) "May ") ? "05" : \
  76.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jun ") ? "06" : \
  77.    *((uint32_t *) __DATE__) == *((uint32_t *) "Jul ") ? "07" : \
  78.    *((uint32_t *) __DATE__) == *((uint32_t *) "Aug ") ? "08" : \
  79.    *((uint32_t *) __DATE__) == *((uint32_t *) "Sep ") ? "09" : \
  80.    *((uint32_t *) __DATE__) == *((uint32_t *) "Oct ") ? "10" : \
  81.    *((uint32_t *) __DATE__) == *((uint32_t *) "Nov ") ? "11" : \
  82.    *((uint32_t *) __DATE__) == *((uint32_t *) "Dec ") ? "12" : \
  83.    "XX" \
  84. ) // compiler will optimize this into a const string, e.g. "11"
  85. #define BUILDDATE_DAY ( \
  86.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  1 ") ? "01" : \
  87.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  2 ") ? "02" : \
  88.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  3 ") ? "03" : \
  89.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  4 ") ? "04" : \
  90.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  5 ") ? "05" : \
  91.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  6 ") ? "06" : \
  92.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  7 ") ? "07" : \
  93.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  8 ") ? "08" : \
  94.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) "  9 ") ? "09" : \
  95.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 10 ") ? "10" : \
  96.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 11 ") ? "11" : \
  97.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 12 ") ? "12" : \
  98.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 13 ") ? "13" : \
  99.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 14 ") ? "14" : \
  100.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 15 ") ? "15" : \
  101.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 16 ") ? "16" : \
  102.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 17 ") ? "17" : \
  103.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 18 ") ? "18" : \
  104.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 19 ") ? "19" : \
  105.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 20 ") ? "20" : \
  106.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 21 ") ? "21" : \
  107.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 22 ") ? "22" : \
  108.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 23 ") ? "23" : \
  109.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 24 ") ? "24" : \
  110.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 25 ") ? "25" : \
  111.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 26 ") ? "26" : \
  112.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 27 ") ? "27" : \
  113.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 28 ") ? "28" : \
  114.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \
  115.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \
  116.    *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \
  117.    "XX" \
  118. ) // compiler will optimize this into a const string, e.g. "14"
  119. #define VERSION_FMT_YYYYMMDD "%s%s%s"
  120. #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY
  121. #endif // !VERSION_ARG_YYYYMMDD
  122.  
  123.  
  124. char *array_contains (int argc, char **argv, char *needle, int mode)
  125. {
  126.    char *arg;
  127.    int arg_index;
  128.    size_t needle_len = strlen (needle);
  129.    for (arg_index = 1; arg_index < argc; arg_index++)
  130.    {
  131.       arg = argv[arg_index];
  132.       if (mode == ARGMODE_SINGLE)
  133.       {
  134.          if (strcmp (arg, needle) == 0)
  135.             return ("");
  136.       }
  137.       else if (mode == ARGMODE_HASVAL)
  138.       {
  139.          if ((arg_index + 1 < argc) && (strcmp (arg, needle) == 0))
  140.             return (argv[arg_index + 1]);
  141.          else if ((strncmp (arg, needle, needle_len) == 0) && (arg[needle_len] != 0))
  142.             return (&arg[needle_len]);
  143.       }
  144.       else if (mode == ARGMODE_EQUALVAL)
  145.       {
  146.          if ((strncmp (arg, needle, needle_len) == 0) && (arg[needle_len] == '='))
  147.             return (&arg[needle_len + 1]);
  148.       }
  149.    }
  150.    return (NULL);
  151. }
  152.  
  153.  
  154. char *resolve_envvars (char *str)
  155. {
  156.    char *out_str = strdup (str), *new_str;
  157.    char *varstart, *varstop, *varval;
  158.    while ((varstart = strstr (out_str, "${")) != NULL)
  159.    {
  160.       *varstart = 0;
  161.       varstart += 2;
  162.       varstop = strchr (varstart, '}');
  163.       *varstop = 0;
  164.       varval = getenv (varstart);
  165.       asprintf (&new_str, "%s%s%s", out_str, (varval != NULL ? varval : ""), varstop + 1);
  166.       free (out_str);
  167.       out_str = new_str;
  168.    }
  169.    return (out_str);
  170. }
  171.  
  172.  
  173. char *makefmtstr (const char *fmt, ...)
  174. {
  175.    va_list ap;
  176.    char *outstr = NULL;
  177.    va_start (ap, fmt);
  178.    vasprintf (&outstr, fmt, ap);
  179.    va_end (ap);
  180.    return (outstr);
  181. }
  182.  
  183.  
  184. int main (int argc, char **argv, char **envp)
  185. {
  186.    #define ADD_CHAR_ARRAY(array_var,arraysize_var,val) do { \
  187.       void *reallocated_ptr = realloc (array_var, (arraysize_var + 2) * sizeof (char *)); \
  188.       if (reallocated_ptr == NULL) exit (1); \
  189.       array_var = reallocated_ptr; \
  190.       array_var[arraysize_var] = (val); \
  191.       array_var[arraysize_var + 1] = NULL; \
  192.       arraysize_var++; \
  193.    } while (0)
  194.    #define ADD_LINKER_ARG(val) ADD_CHAR_ARRAY (linker_argv, linker_argc, (val))
  195.    #define ADD_L_ARG(val) ADD_CHAR_ARRAY (largs, larg_count, (val))
  196.    #define ADD_O_ARG(val) ADD_CHAR_ARRAY (oargs, oarg_count, (val))
  197.    #define ADD_S_ARG(val) ADD_CHAR_ARRAY (sargs, sarg_count, (val))
  198.    #define ARGV_CONTAINS_SINGLEARG(val)       ((arg = array_contains (argc, argv, (val), ARGMODE_SINGLE))   != NULL)
  199.    #define ARGV_CONTAINS_ARGWITHVAL(val)      ((arg = array_contains (argc, argv, (val), ARGMODE_HASVAL))   != NULL)
  200.    #define ARGV_CONTAINS_ARGWITHEQUALVAL(val) ((arg = array_contains (argc, argv, (val), ARGMODE_EQUALVAL)) != NULL)
  201.    #define ARGV_SINGLEARG(val)       array_contains (argc, argv, (val), ARGMODE_SINGLE)
  202.    #define ARGV_ARGWITHVAL(val)      array_contains (argc, argv, (val), ARGMODE_HASVAL)
  203.    #define ARGV_ARGWITHEQUALVAL(val) array_contains (argc, argv, (val), ARGMODE_EQUALVAL)
  204.  
  205.    static char filebuf[1024 * 1024];
  206.    char **linker_argv = NULL;
  207.    size_t linker_argc = 0;
  208.    char **largs = NULL; // array of "-lxxx" arguments
  209.    size_t larg_count = 0;
  210.    char **sargs = NULL; // array of source files arguments
  211.    size_t sarg_count = 0;
  212.    char **oargs = NULL; // array of object files arguments
  213.    size_t oarg_count = 0;
  214.    size_t read_count;
  215.    size_t byte_index;
  216.    bool was_cpluspluslib_included = false;
  217.    bool requires_libcplusplus = false;
  218.    int arg_index;
  219.    char *arg;
  220.    FILE *fp;
  221.  
  222.    // special case: print the driver version and exit
  223.    if ((argc == 2) && (strcmp (argv[1], "--driver-version") == 0))
  224.    {
  225.       printf ("clang 'gcc' linker driver for QNX 8.0 version " VERSION_FMT_YYYYMMDD " by Pierre-Marie Baty <pm@pmbaty.com>\n", VERSION_ARG_YYYYMMDD);
  226.       return (0);
  227.    }
  228.  
  229.    // if *any* of these flags are present, it means we don't want to link anything, so direct everything to the compiler
  230.    if (   ARGV_CONTAINS_SINGLEARG ("-fsyntax-only")
  231.        || ARGV_CONTAINS_SINGLEARG ("-c")
  232.        || ARGV_CONTAINS_SINGLEARG ("-M")
  233.        || ARGV_CONTAINS_SINGLEARG ("-MM")
  234.        || ARGV_CONTAINS_SINGLEARG ("-E")
  235.        || ARGV_CONTAINS_SINGLEARG ("-S"))
  236.    {
  237.       if (ARGV_CONTAINS_SINGLEARG ("-c"))
  238.          for (arg_index = 1; arg_index < argc; arg_index++)
  239.             if (strcmp (argv[arg_index], "-shared") == 0)
  240.                argv[arg_index] = ""; // HACK for GNU autotools: when compiling, wipe out the -shared flag to avoid a warning
  241.       execvpe (COMPILER, argv, envp); // by leaving argv[0] untouched, we will be invoking Clang as 'gcc', which will give it a supplemental hint about how to behave
  242.    }
  243.  
  244.    // collect source and object files in two separate lists
  245.    for (arg_index = 1; arg_index < argc; arg_index++)
  246.       if ((strcmp (argv[arg_index - 1], "-o") != 0) // this arg is NOT preceded by "-o"...
  247.           && (access (argv[arg_index], 0) == 0) // ... this arg is an existing file...
  248.           && ((arg = strrchr (argv[arg_index], '.')) != NULL)) // this filename has an extension (FIXME: what if "-x <language>" is specified?)
  249.       {
  250.          if (   (strcasecmp (arg, ".s") == 0)
  251.              || (strcasecmp (arg, ".c") == 0)
  252.              || (strcasecmp (arg, ".cc") == 0)
  253.              || (strcasecmp (arg, ".c++") == 0)
  254.              || (strcasecmp (arg, ".cpp") == 0)
  255.              || (strcasecmp (arg, ".cxx") == 0)
  256.              || (strcasecmp (arg, ".m") == 0)
  257.              || (strcasecmp (arg, ".mm") == 0)
  258.              || (strcasecmp (arg, ".mxx") == 0))
  259.             ADD_S_ARG (argv[arg_index]); // this file is one of the known source file extensions: add to source files list
  260.          else
  261.             ADD_O_ARG (argv[arg_index]); // this file is NOT one of the known file extensions: add to object files list
  262.       }
  263.  
  264.    // if we have zero .o file, OR if we have some source files, we have to compile first
  265.    if ((sarg_count > 0) || (oarg_count == 0))
  266.    {
  267.       if (ARGV_CONTAINS_SINGLEARG ("-c"))
  268.          for (arg_index = 1; arg_index < argc; arg_index++)
  269.             if (strcmp (argv[arg_index], "-shared") == 0)
  270.                argv[arg_index] = ""; // HACK for GNU autotools: when compiling, wipe out the -shared flag to avoid a warning
  271.       execvpe (COMPILER, argv, envp); // by leaving argv[0] untouched, we will be invoking Clang as 'gcc', which will give it a supplemental hint about how to behave
  272.    }
  273.  
  274.    // collect -l flags
  275.    for (arg_index = 1; arg_index < argc; arg_index++)
  276.       if ((strncmp (argv[arg_index], "-l", 2) == 0) && ((argv[arg_index])[2] != 0))
  277.          ADD_L_ARG (argv[arg_index]);
  278.  
  279.    //   LINKER " "
  280.    ADD_LINKER_ARG (LINKER);
  281.  
  282.    //   "%{!fno-use-linker-plugin:"
  283.    //           "%{!fno-lto:     "
  284.    //                   "-plugin ${QNX_HOST}/usr/lib/gcc/" TARGET_TRIPLE "/" BASEVER "/liblto_plugin.so     "
  285.    //                   "-plugin-opt=${QNX_HOST}/usr/lib/gcc/" TARGET_TRIPLE "/" BASEVER "/lto-wrapper     "
  286.    //                   "-plugin-opt=-fresolution=%u.res         "
  287.    //                   "%{flinker-output=*:"   "-plugin-opt=-linker-output-known"      "}     "
  288.    //                   "%{!nostdlib:"
  289.    //                           "%{!nodefaultlibs:"     "%:pass-through-libs(%(link_gcc_c_sequence))"   "}"
  290.    //                   "}     "
  291.    //           "}"
  292.    //   "}"
  293.    if (!ARGV_CONTAINS_SINGLEARG ("-fno-use-linker-plugin") && !ARGV_CONTAINS_SINGLEARG ("-fno-lto"))
  294.    {
  295.       /*ADD_LINKER_ARG ("-plugin");
  296.       ADD_LINKER_ARG (resolve_envvars ("${QNX_HOST}/usr/lib/gcc/" TARGET_TRIPLE "/" BASEVER "/liblto_plugin.so"));
  297.       ADD_LINKER_ARG (resolve_envvars ("-plugin-opt=${QNX_HOST}/usr/lib/gcc/" TARGET_TRIPLE "/" BASEVER "/lto-wrapper"));
  298.       ADD_LINKER_ARG (makefmtstr ("-plugin-opt=-fresolution=%s.res", "TODO-UNKNOWN")); // LTO is not interoperable between clang and ld. See below.
  299.       if (ARGV_CONTAINS_ARGWITHEQUALVAL ("-flinker-output"))
  300.          ADD_LINKER_ARG ("-plugin-opt=-linker-output-known");
  301.       if (!ARGV_CONTAINS_SINGLEARG ("-nostdlib") && !ARGV_CONTAINS_SINGLEARG ("-nodefaultlibs"))
  302.          for (arg_index = 0; arg_index < larg_count; arg_index++)
  303.             ADD_LINKER_ARG (makefmtstr ("-plugin-opt=-pass-through=%s", largs[arg_index]));*/
  304.  
  305.       // looks like LTO is a no-go. See: https://stackoverflow.com/questions/51259340/interoperability-between-clang-gcc-and-lto
  306.    }
  307.  
  308.    //   "%{flto|flto=*:"        "%<fcompare-debug*"     "}     "
  309.    if (ARGV_CONTAINS_SINGLEARG ("-flto") || ARGV_CONTAINS_ARGWITHEQUALVAL ("-flto"))
  310.       for (arg_index = 1; arg_index < argc; arg_index++)
  311.          if (strncmp (argv[arg_index], "-fcompare-debug", 15) == 0)
  312.             argv[arg_index] = ""; // remove this arg
  313.  
  314.    if (ARGV_CONTAINS_SINGLEARG ("-flto"))       ADD_LINKER_ARG ("-flto");                    // "%{flto} "
  315.    if (ARGV_CONTAINS_SINGLEARG ("-fno-lto"))    ADD_LINKER_ARG ("-fno-lto");                 // "%{fno-lto} "
  316.    if (ARGV_CONTAINS_ARGWITHEQUALVAL ("-flto")) ADD_LINKER_ARG (makefmtstr ("-flto=%s", arg)); //       "%{flto=*} "
  317.  
  318.    //   "%{!static:"    "--eh-frame-hdr"                "} "
  319.    if (!ARGV_CONTAINS_SINGLEARG ("-static")) ADD_LINKER_ARG ("--eh-frame-hdr");
  320.  
  321. #if IS_TARGET_INTEL
  322.    //   "%{!m32:"       "-m elf_x86_64"                 "} "
  323.    //   "%{m32:"        "-m i386nto"                    "}   "
  324.    ADD_LINKER_ARG ("-m");
  325.    if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  326.       ADD_LINKER_ARG ("i386nto");
  327.    else
  328.       ADD_LINKER_ARG ("elf_x86_64");
  329. #endif // IS_TARGET_INTEL
  330.  
  331.    //   "%{h*} "
  332.    for (arg_index = 1; arg_index < argc; arg_index++)
  333.       if ((strcmp (argv[arg_index], "-h") == 0) && (arg_index + 1 < argc))
  334.       {
  335.          ADD_LINKER_ARG ("-h");
  336.          ADD_LINKER_ARG (argv[++arg_index]);
  337.       }
  338.       else if ((strncmp (argv[arg_index], "-h", 2) == 0) && ((argv[arg_index])[2] != 0))
  339.          ADD_LINKER_ARG (argv[arg_index]);
  340.    
  341.    //   "%{v:"  "-V"    "}   "
  342.    if (ARGV_CONTAINS_SINGLEARG ("-v")) ADD_LINKER_ARG ("-V");
  343.  
  344.    //   "%{b}   "
  345.    if (ARGV_CONTAINS_SINGLEARG ("-b")) ADD_LINKER_ARG ("-b");
  346.  
  347. #if !IS_TARGET_INTEL
  348.    //   "%{Wl,*:"       "%*"                            "}  "
  349.    for (arg_index = 1; arg_index < argc; arg_index++)
  350.       if ((strcmp (argv[arg_index], "-Wl,") == 0) && (arg_index + 1 < argc))
  351.          ADD_LINKER_ARG (argv[++arg_index]);
  352.       else if ((strncmp (argv[arg_index], "-Wl,", 4) == 0) && ((argv[arg_index])[4] != 0))
  353.          ADD_LINKER_ARG (argv[arg_index] + 4);
  354. #endif // !IS_TARGET_INTEL
  355.  
  356.    //   "%{!r:"         "--build-id=md5"                "}   "
  357.    if (!ARGV_CONTAINS_SINGLEARG ("-r")) ADD_LINKER_ARG ("--build-id=md5");
  358.  
  359.    //   "--warn-shared-textrel   "
  360.    //   "-zrelro "
  361.    //   "-znow   "
  362.    ADD_LINKER_ARG ("--warn-shared-textrel");
  363.    ADD_LINKER_ARG ("-zrelro"); // set relocations to be read-only
  364.    ADD_LINKER_ARG ("-znow"); // do immediate binding of dylibs (the opposite would be -zlazy, which is less secure)
  365.  
  366.    // since clang doesn't seem to generate .note.GNU-stack sections in output ELF files we explicitly specify the linker that we don't want an executable stack
  367.    // TODO: fix this in clang itself
  368.    ADD_LINKER_ARG ("-znoexecstack");
  369.  
  370. #if IS_TARGET_INTEL
  371.    //   "%{shared:"     "-G -dy -z text"                "}   "
  372.    if (ARGV_CONTAINS_SINGLEARG ("-shared"))
  373.    {
  374.       ADD_LINKER_ARG ("-G");
  375.       ADD_LINKER_ARG ("-dy");
  376.       ADD_LINKER_ARG ("-z");
  377.       ADD_LINKER_ARG ("text");
  378.    }
  379.  
  380.    //   "%{symbolic:"   "-Bsymbolic -G -dy -z text"     "}   "
  381.    if (ARGV_CONTAINS_SINGLEARG ("-symbolic"))
  382.    {
  383.       ADD_LINKER_ARG ("-Bsymbolic");
  384.       ADD_LINKER_ARG ("-G");
  385.       ADD_LINKER_ARG ("-dy");
  386.       ADD_LINKER_ARG ("-z");
  387.       ADD_LINKER_ARG ("text");
  388.    }
  389.  
  390.    //   "%{G:"          "-G"                            "}   "
  391.    if (ARGV_CONTAINS_SINGLEARG ("-G")) ADD_LINKER_ARG ("-G");
  392.  
  393.    //   "%{shared:"     "-shared"                       "}   "
  394.    //   "%{!shared:     "
  395.    //           "%{!static:       "
  396.    //                   "%{rdynamic:"   "-export-dynamic"               "}       "
  397.    //                   "%{m32:"
  398.    //                           "%{!dynamic-linker:"    "-dynamic-linker /usr/lib/ldqnx.so.2"           "}"
  399.    //                   "}       "
  400.    //                   "%{!m32:"
  401.    //                           "%{!dynamic-linker:"    "-dynamic-linker /usr/lib/ldqnx-64.so.2"        "}"
  402.    //                   "}"
  403.    //           "}     "
  404.    //           "%{static:"     "-static"                                                               "}"
  405.    //   "} "
  406.    if (ARGV_CONTAINS_SINGLEARG ("-shared"))
  407.       ADD_LINKER_ARG ("-shared");
  408.    else if (ARGV_CONTAINS_SINGLEARG ("-static"))
  409.       ADD_LINKER_ARG ("-static");
  410.    else
  411.    {
  412.       if (ARGV_CONTAINS_SINGLEARG ("-rdynamic"))
  413.          ADD_LINKER_ARG ("-export-dynamic");
  414.       if (!ARGV_CONTAINS_SINGLEARG ("-dynamic-linker"))
  415.       {
  416.          ADD_LINKER_ARG ("-dynamic-linker");
  417.          if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  418.             ADD_LINKER_ARG ("/usr/lib/ldqnx.so.2");
  419.          else // not -m32
  420.             ADD_LINKER_ARG ("/usr/lib/ldqnx-64.so.2");
  421.       }
  422.    }
  423.  
  424. #else // !IS_TARGET_INTEL
  425.    //   "%{static:"     "-Bstatic"                      "}  "
  426.    if (ARGV_CONTAINS_SINGLEARG ("-static")) ADD_LINKER_ARG ("-Bstatic");
  427.  
  428.    //   "%{shared}  "
  429.    if (ARGV_CONTAINS_SINGLEARG ("-shared")) ADD_LINKER_ARG ("-shared");
  430.  
  431.    //   "%{symbolic:"   "-Bsymbolic"                    "}  "
  432.    if (ARGV_CONTAINS_SINGLEARG ("-symbolic")) ADD_LINKER_ARG ("-Bsymbolic");
  433.  
  434.    //   "%{G:"          "-G"                            "} "
  435.    if (ARGV_CONTAINS_SINGLEARG ("-G")) ADD_LINKER_ARG ("-G");
  436.  
  437.    //   "%{MAP:"        "-Map mapfile"                  "}  "
  438.    if (ARGV_CONTAINS_SINGLEARG ("-MAP"))
  439.    {
  440.       ADD_LINKER_ARG ("-Map");
  441.       ADD_LINKER_ARG ("mapfile");
  442.    }
  443.  
  444.    //   "%{!shared:    "
  445.    //           "%{!static:      "
  446.    //                   "%{rdynamic:"   "-export-dynamic"               "}"
  447.    //           "}    "
  448.    //           "--dynamic-linker /usr/lib/ldqnx-64.so.2"
  449.    //   "}  "
  450.    if (!ARGV_CONTAINS_SINGLEARG ("-shared"))
  451.    {
  452.       if (!ARGV_CONTAINS_SINGLEARG ("-static") && ARGV_CONTAINS_SINGLEARG ("-rdynamic"))
  453.          ADD_LINKER_ARG ("-export-dynamic");
  454.       ADD_LINKER_ARG ("--dynamic-linker");
  455.       ADD_LINKER_ARG ("/usr/lib/ldqnx-64.so.2");
  456.    }
  457.  
  458.    //   "-X "
  459.    ADD_LINKER_ARG ("-X");
  460.  
  461.    //   "%{EB:"         "-EB"                           "} "
  462.    //   "%{!EB:"        "-EL"                           "} "
  463.    if (ARGV_CONTAINS_SINGLEARG ("-EB"))
  464.       ADD_LINKER_ARG ("-EB");
  465.    else
  466.       ADD_LINKER_ARG ("-EL");
  467.  
  468.    //   "%{EL:"         "-EL"                           "} "
  469.    if (ARGV_CONTAINS_SINGLEARG ("-EL"))
  470.       ADD_LINKER_ARG ("-EL");
  471. #endif // IS_TARGET_INTEL
  472.  
  473.    //   "%{static|shared|r:;!no-pie:"   "-pie"                                                          "} "
  474.    if (ARGV_CONTAINS_SINGLEARG ("-static") || !ARGV_CONTAINS_SINGLEARG ("-shared") || !ARGV_CONTAINS_SINGLEARG ("-r"))
  475.       ; // nothing to do
  476.    else if (!ARGV_CONTAINS_SINGLEARG ("-no-pie"))
  477.       ADD_LINKER_ARG ("-pie");
  478.  
  479.    //   "%{fuse-ld=*:"                  "-fuse-ld=%*"                                                                   "} "
  480.    for (arg_index = 1; arg_index < argc; arg_index++)
  481.       if ((strncmp (argv[arg_index], "-fuse-ld=", 9) == 0) && ((argv[arg_index])[9] != 0))
  482.          ADD_LINKER_ARG (argv[arg_index]);
  483.  
  484.    //   "%{gz|gz=zlib:"         "--compress-debug-sections=zlib"                        "} "
  485.    //   "%{gz=none:"                    "--compress-debug-sections=none"                        "} "
  486.    //   "%{gz=zlib-gnu:"                "--compress-debug-sections=zlib-gnu"    "} "
  487.    if (ARGV_CONTAINS_SINGLEARG ("-gz") || ARGV_CONTAINS_SINGLEARG ("-gz=zlib"))
  488.       ADD_LINKER_ARG ("--compress-debug-sections=zlib");
  489.    if (ARGV_CONTAINS_SINGLEARG ("-gz=none"))
  490.       ADD_LINKER_ARG ("--compress-debug-sections=none");
  491.    if (ARGV_CONTAINS_SINGLEARG ("-gz=zlib-gnu"))
  492.       ADD_LINKER_ARG ("--compress-debug-sections=zlib-gnu");
  493.  
  494.    //   "%X "
  495.    // nothing to do (nothing was accumulated by %x previously)
  496.  
  497.    //   "%{o*} "
  498.    for (arg_index = 1; arg_index < argc; arg_index++)
  499.       if ((strcmp (argv[arg_index], "-o") == 0) && (arg_index + 1 < argc))
  500.       {
  501.          ADD_LINKER_ARG ("-o");
  502.          ADD_LINKER_ARG (argv[++arg_index]);
  503.       }
  504.       else if ((strncmp (argv[arg_index], "-o", 2) == 0) && ((argv[arg_index])[2] != 0))
  505.          ADD_LINKER_ARG (argv[arg_index]);
  506.  
  507.    //   "%{e*} "
  508.    for (arg_index = 1; arg_index < argc; arg_index++)
  509.       if ((strcmp (argv[arg_index], "-e") == 0) && (arg_index + 1 < argc))
  510.       {
  511.          ADD_LINKER_ARG ("-e");
  512.          ADD_LINKER_ARG (argv[++arg_index]);
  513.       }
  514.       else if ((strncmp (argv[arg_index], "-e", 2) == 0) && ((argv[arg_index])[2] != 0))
  515.          ADD_LINKER_ARG (argv[arg_index]);
  516.  
  517.    //   "%{N} "
  518.    //   "%{n} "
  519.    //   "%{r}    "
  520.    //   "%{s} "
  521.    //   "%{t} "
  522.    if (ARGV_CONTAINS_SINGLEARG ("-N")) ADD_LINKER_ARG ("-N");
  523.    if (ARGV_CONTAINS_SINGLEARG ("-n")) ADD_LINKER_ARG ("-n");
  524.    if (ARGV_CONTAINS_SINGLEARG ("-r")) ADD_LINKER_ARG ("-r");
  525.    if (ARGV_CONTAINS_SINGLEARG ("-s")) ADD_LINKER_ARG ("-s");
  526.    if (ARGV_CONTAINS_SINGLEARG ("-t")) ADD_LINKER_ARG ("-t");
  527.  
  528.    //   "%{u*} "
  529.    for (arg_index = 1; arg_index < argc; arg_index++)
  530.       if ((strcmp (argv[arg_index], "-u") == 0) && (arg_index + 1 < argc))
  531.       {
  532.          ADD_LINKER_ARG ("-u");
  533.          ADD_LINKER_ARG (argv[++arg_index]);
  534.       }
  535.       else if ((strncmp (argv[arg_index], "-u", 2) == 0) && ((argv[arg_index])[2] != 0))
  536.          ADD_LINKER_ARG (argv[arg_index]);
  537.  
  538.    //   "%{z} "
  539.    //   "%{Z} "
  540.    if (ARGV_CONTAINS_SINGLEARG ("-z")) ADD_LINKER_ARG ("-z");
  541.    if (ARGV_CONTAINS_SINGLEARG ("-Z")) ADD_LINKER_ARG ("-Z");
  542.  
  543.    //   "%{!nostdlib:"
  544.    //           "%{!r:"
  545.    //                   "%{!nostartfiles:"      "%S"    "}"
  546.    //           "}"
  547.    //   "}     "
  548.    if (!ARGV_CONTAINS_SINGLEARG ("-nostdlib") && !ARGV_CONTAINS_SINGLEARG ("-r") && !ARGV_CONTAINS_SINGLEARG ("-nostartfiles"))
  549.    {
  550. #if IS_TARGET_INTEL // Intel variant
  551.       //        "%{!shared:   "
  552.       //                "%{!symbolic:     "
  553.       //                        "%{pg:       "
  554.       //                                "%{m32:"        " %${QNX_TARGET}/x86/lib/mcrt1.o%s"     "}       "
  555.       //                                "%{!m32:"       " %${QNX_TARGET}/x86_64/lib/mcrt1.o%s"  "}"
  556.       //                        "}     "
  557.       //                        "%{!pg:       "
  558.       //                                "%{p:        "
  559.       //                                        "%{m32:"        " %${QNX_TARGET}/x86/lib/mcrt1.o%s"     "}        "
  560.       //                                        "%{!m32:"       " %${QNX_TARGET}/x86_64/lib/mcrt1.o%s"  "}"
  561.       //                                "}"
  562.       //                        "}     "
  563.       //                        "%{!p: "
  564.       //                                "%{!pg:        "
  565.       //                                        "%{m32:"        " %${QNX_TARGET}/x86/lib/crt1%{!no-pie:S}.o%s"  "}        "
  566.       //                                        "%{!m32:"       " %${QNX_TARGET}/x86_64/lib/crt1.o%s"   "}"
  567.       //                                "}"
  568.       //                        "}     "
  569.       //                "}"
  570.       //        "}     "
  571.       if (!ARGV_CONTAINS_SINGLEARG ("-shared") && !ARGV_CONTAINS_SINGLEARG ("-symbolic"))
  572.       {
  573.          if (ARGV_CONTAINS_SINGLEARG ("-pg") || ARGV_CONTAINS_SINGLEARG ("-p"))
  574.          {
  575.             if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  576.                ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86/lib/mcrt1.o"));
  577.             else
  578.                ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86_64/lib/mcrt1.o"));
  579.          }
  580.          else // neither "-pg" nor "-p"
  581.          {
  582.             if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  583.                ADD_LINKER_ARG (resolve_envvars (makefmtstr ("${QNX_TARGET}/x86/lib/crt1%s.o", ARGV_CONTAINS_SINGLEARG ("-no-pie") ? "" : "S")));
  584.             else
  585.                ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86_64/lib/crt1.o"));
  586.          }
  587.       }
  588.  
  589.       //        "%{m32:"        " %${QNX_TARGET}/x86/lib/crti.o%s"      "}     "
  590.       //        "%{!m32:"       " %${QNX_TARGET}/x86_64/lib/crti.o%s"   "}     "
  591.       if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  592.          ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86/lib/crti.o"));
  593.       else
  594.          ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86_64/lib/crti.o"));
  595. #else // !IS_TARGET_INTEL
  596.       //        "%{!shared: %${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/lib/%{pg:m}%{p:m}crt1.o } "
  597.       if (ARGV_CONTAINS_SINGLEARG ("-shared"))
  598.          if (ARGV_CONTAINS_SINGLEARG ("-EB"))
  599.             ADD_LINKER_ARG (resolve_envvars (makefmtstr ("${QNX_TARGET}/aarch64be/lib/%scrt1.o", ARGV_CONTAINS_SINGLEARG ("-pg") || ARGV_CONTAINS_SINGLEARG ("-p") ? "m" : "")));
  600.          else
  601.             ADD_LINKER_ARG (resolve_envvars (makefmtstr ("${QNX_TARGET}/aarch64le/lib/%scrt1.o", ARGV_CONTAINS_SINGLEARG ("-pg") || ARGV_CONTAINS_SINGLEARG ("-p") ? "m" : "")));
  602.  
  603.       //        "%${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/lib/crti.o "
  604.       if (ARGV_CONTAINS_SINGLEARG ("-EB"))
  605.          ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64be/lib/crti.o"));
  606.       else
  607.          ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64le/lib/crti.o"));
  608. #endif // IS_TARGET_INTEL
  609.       //        "crtbegin.o%s "
  610.       ADD_LINKER_ARG (resolve_envvars ("${QNX_HOST}/usr/bin/../lib/gcc/" TARGET_TRIPLE "/" BASEVER "/crtbegin.o"));
  611.    }
  612.  
  613.    //   "%{static|no-pie|static-pie:"                                   "} "
  614.    // nothing to do
  615.  
  616.    //   "%@{L*} "
  617.    for (arg_index = 1; arg_index < argc; arg_index++)
  618.       if ((strcmp (argv[arg_index], "-L") == 0) && (arg_index + 1 < argc))
  619.       {
  620.          ADD_LINKER_ARG ("-L");
  621.          ADD_LINKER_ARG (argv[++arg_index]);
  622.       }
  623.       else if ((strncmp (argv[arg_index], "-L", 2) == 0) && ((argv[arg_index])[2] != 0))
  624.          ADD_LINKER_ARG (argv[arg_index]);
  625.  
  626.    //   "%(mfwrap) "
  627.    // nothing to do (looks like the libmudflap wrap spec has been officially removed from this version of GCC, except for uCLinux)
  628.  
  629.    //   "-L${QNX_HOST}/usr/bin/../lib/gcc/" TARGET_TRIPLE "/" BASEVER
  630.    //   "-L${QNX_HOST}/usr/bin/../lib/gcc"
  631.    ADD_LINKER_ARG (resolve_envvars ("-L${QNX_HOST}/usr/bin/../lib/gcc/" TARGET_TRIPLE "/" BASEVER));
  632.    ADD_LINKER_ARG (resolve_envvars ("-L${QNX_HOST}/usr/bin/../lib/gcc"));
  633.  
  634. #if IS_TARGET_INTEL
  635.    //   "%{m32:   " \
  636.    //           "-L %${QNX_TARGET}/x86/lib/gcc/" BASEVER "   "
  637.    //           "-L %${QNX_TARGET}/x86/lib   "
  638.    //           "-L %${QNX_TARGET}/x86/usr/lib   "
  639.    //           "-L %${QNX_TARGET}/x86/opt/lib   "
  640.    //           "-rpath-link %${QNX_TARGET}/x86/lib/gcc/" BASEVER ":%${QNX_TARGET}/x86/lib:%${QNX_TARGET}/x86/usr/lib:%${QNX_TARGET}/x86/opt/lib"
  641.    //   "}  "
  642.    //   "%{!m32:   "
  643.    //           "-L %${QNX_TARGET}/x86_64/lib/gcc/" BASEVER "   "
  644.    //           "-L %${QNX_TARGET}/x86_64/lib   "
  645.    //           "-L %${QNX_TARGET}/x86_64/usr/lib   "
  646.    //           "-L %${QNX_TARGET}/x86_64/opt/lib   "
  647.    //           "-rpath-link %${QNX_TARGET}/x86_64/lib/gcc/" BASEVER ":%${QNX_TARGET}/x86_64/lib:%${QNX_TARGET}/x86_64/usr/lib:%${QNX_TARGET}/x86_64/opt/lib"
  648.    //   "} "
  649.    if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  650.    {
  651.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86/lib/gcc/" BASEVER));
  652.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86/lib"));
  653.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86/usr/lib"));
  654.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86/opt/lib"));
  655.       ADD_LINKER_ARG ("-rpath-link");
  656.       ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86/lib/gcc/" BASEVER ":${QNX_TARGET}/x86/lib" ":${QNX_TARGET}/x86/usr/lib" ":${QNX_TARGET}/x86/opt/lib"));
  657.    }
  658.    else
  659.    {
  660.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86_64/lib/gcc/" BASEVER));
  661.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86_64/lib"));
  662.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86_64/usr/lib"));
  663.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/x86_64/opt/lib"));
  664.       ADD_LINKER_ARG ("-rpath-link");
  665.       ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86_64/lib/gcc/" BASEVER ":${QNX_TARGET}/x86_64/lib:${QNX_TARGET}/x86_64/usr/lib:${QNX_TARGET}/x86_64/opt/lib"));
  666.    }
  667. #else // !IS_TARGET_INTEL
  668.    //   "-L %${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/lib/gcc/" BASEVER "  "
  669.    //   "-L %${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/lib  "
  670.    //   "-L %${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/usr/lib  "
  671.    //   "-L %${QNX_TARGET}/aarch64%{EB:be}%{!EB:le}/opt/lib  "
  672.    if (ARGV_CONTAINS_SINGLEARG ("-EB"))
  673.    {
  674.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64be/lib/gcc/" BASEVER));
  675.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64be/lib"));
  676.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64be/usr/lib"));
  677.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64be/opt/lib"));
  678.       ADD_LINKER_ARG ("-rpath-link");
  679.       ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64be/lib/gcc/" BASEVER ":${QNX_TARGET}/aarch64be/lib" ":${QNX_TARGET}/aarch64be/usr/lib" ":${QNX_TARGET}/aarch64be/opt/lib"));
  680.    }
  681.    else
  682.    {
  683.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64le/lib/gcc/" BASEVER));
  684.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64le/lib"));
  685.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64le/usr/lib"));
  686.       ADD_LINKER_ARG (resolve_envvars ("-L${QNX_TARGET}/aarch64le/opt/lib"));
  687.       ADD_LINKER_ARG ("-rpath-link");
  688.       ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64le/lib/gcc/" BASEVER ":${QNX_TARGET}/aarch64le/lib" ":${QNX_TARGET}/aarch64le/usr/lib" ":${QNX_TARGET}/aarch64le/opt/lib"));
  689.    }
  690. #endif // IS_TARGET_INTEL
  691.  
  692.    //   "%{!nostdlib:"
  693.    //           "%{!r:"
  694.    //                   "%{fvtable-verify=std:"         " -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end"        "}    "
  695.    //                   "%{fvtable-verify=preinit:"     " -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end"        "}"
  696.    //           "}"
  697.    //   "} "
  698.    if (!ARGV_CONTAINS_SINGLEARG ("-nostdlib") && !ARGV_CONTAINS_SINGLEARG ("-r"))
  699.    {
  700.       if (ARGV_CONTAINS_SINGLEARG ("-fvtable-verify=std") || ARGV_CONTAINS_SINGLEARG ("-fvtable-verify=preinit"))
  701.       {
  702.          ADD_LINKER_ARG ("-lvtv");
  703.          ADD_LINKER_ARG ("-u_vtable_map_vars_start");
  704.          ADD_LINKER_ARG ("-u_vtable_map_vars_end");
  705.       }
  706.  
  707.       //        "%{!nodefaultlibs:"
  708.       if (!ARGV_CONTAINS_SINGLEARG ("-nodefaultlibs"))
  709.       {
  710. #if IS_TARGET_INTEL
  711.       //                "%{%:sanitize(address):"        "}     "
  712.       //                "%{%:sanitize(hwaddress):"      "}     "
  713.       //                "%{%:sanitize(thread):"         "}     "
  714.       //                "%{%:sanitize(leak):"           "}"
  715.       /* TODO */
  716. #else // !IS_TARGET_INTEL
  717.       //                "%{%:sanitize(address):"
  718.       //                        "%{!shared:"            "libasan_preinit%O%s"                                                                           "} "
  719.       //                        "%{static-libasan:"     "%{!shared:"    "-Bstatic --whole-archive -lasan --no-whole-archive -Bdynamic"          "}"     "}"
  720.       //                        "%{!static-libasan:"    "-lasan"                                                                                        "}"
  721.       //                "}     "
  722.       //                "%{%:sanitize(hwaddress):"
  723.       //                        "%{static-libhwasan:"   "%{!shared:"    "-Bstatic --whole-archive -lhwasan --no-whole-archive -Bdynamic"        "}"     "}"
  724.       //                        "%{!static-libhwasan:"  "-lhwasan"                                                                                      "}"
  725.       //                "}     "
  726.       //                "%{%:sanitize(thread):"
  727.       //                        "%{!shared:"            "libtsan_preinit%O%s"                                                                           "} "
  728.       //                        "%{static-libtsan:"     "%{!shared:"    "-Bstatic --whole-archive -ltsan --no-whole-archive -Bdynamic"          "}"     "}"
  729.       //                        "%{!static-libtsan:"    "-ltsan"                                                                                        "}"
  730.       //                "}     "
  731.       //                "%{%:sanitize(leak):"
  732.       //                        "%{!shared:"            "liblsan_preinit%O%s"                                                                           "} "
  733.       //                        "%{static-liblsan:"     "%{!shared:"    "-Bstatic --whole-archive -llsan --no-whole-archive -Bdynamic"          "}"     "}"
  734.       //                        "%{!static-liblsan:"    "-llsan"                                                                                        "}"
  735.       //                "}"
  736.       /* TODO */
  737. #endif // IS_TARGET_INTEL
  738.       }
  739.    }
  740.  
  741.    //   "%o      "
  742.    for (arg_index = 0; arg_index < oarg_count; arg_index++)
  743.       ADD_LINKER_ARG (oargs[arg_index]);
  744.  
  745.    // QUOTE FROM https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html -- BEGIN
  746.    // "The following example inserts the link_gomp spec if the last -ftree-parallelize-loops= option given on the command line is greater than 1:
  747.    //  %{                 %:gt(%{ftree-parallelize-loops=*:%*} 1):%:include(libgomp.spec)%(link_gomp)}"
  748.    // QUOTE FROM https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html -- END
  749.    //   "%{fopenacc|fopenmp|%:gt(%{ftree-parallelize-loops=*:%*} 1):%:include(libgomp.spec)%(link_gomp)}    "
  750.    // nothing to do (link_gomp is an empty string in this GCC)
  751.  
  752.    //   "%{fgnu-tm:"    "%:include(libitm.spec)%(link_itm)"     "}    "
  753.    if (ARGV_CONTAINS_SINGLEARG ("-fgnu-tm"))
  754.    {
  755.       ADD_LINKER_ARG ("-litm");
  756.       ADD_LINKER_ARG ("-lpthread"); // FIXME: possibly wrong
  757.    }
  758.  
  759.    //   "%(mflib)  "
  760.    // nothing to do (looks like the mflib spec has been officially removed from this version of GCC)
  761.  
  762.    //   "%{fsplit-stack: "                              "--wrap=pthread_create"         "}    "
  763.    if (ARGV_CONTAINS_SINGLEARG ("-fsplit-stack"))
  764.       ADD_LINKER_ARG ("--wrap=pthread_create");
  765.  
  766.    //   "%{fprofile-arcs|fprofile-generate*|coverage:"  "-lgcov"                        "} "
  767.    if (ARGV_CONTAINS_SINGLEARG ("-fprofile-arcs") || ARGV_CONTAINS_ARGWITHVAL ("-fprofile-generate") || ARGV_CONTAINS_SINGLEARG ("-coverage"))
  768.       ADD_LINKER_ARG ("-lgcov");
  769.  
  770.    if (!ARGV_CONTAINS_SINGLEARG ("-nostdlib") && !ARGV_CONTAINS_SINGLEARG ("-r"))
  771.    {
  772.       if (!ARGV_CONTAINS_SINGLEARG ("-nodefaultlibs"))
  773.       {
  774. #if IS_TARGET_INTEL
  775.          //     "%{%:sanitize(address):"
  776.          //             "%{static-libasan:"             "-Bstatic"                                              "} "
  777.          //             "-lasan "
  778.          //             "%{static-libasan:"             "-Bdynamic"                                             "} "
  779.          //             "%{static-libasan|static:"      "%:include(libsanitizer.spec)%(link_libasan)"           "}    "
  780.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=address"      "}"
  781.          //     "}    "
  782.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=address"))
  783.          {
  784.             if (ARGV_CONTAINS_SINGLEARG ("-static-libasan")) ADD_LINKER_ARG ("-Bstatic");
  785.             ADD_LINKER_ARG ("-lasan");
  786.             if (ARGV_CONTAINS_SINGLEARG ("-static-libasan")) ADD_LINKER_ARG ("-Bdynamic");
  787.             if (ARGV_CONTAINS_SINGLEARG ("-static-libasan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  788.                ADD_LINKER_ARG ("-lm"); // only known dependency to libasan on QNX
  789.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  790.             {
  791.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=address\n", argv[0]);
  792.                exit (1);
  793.             }
  794.          }
  795.  
  796.          //     "%{%:sanitize(hwaddress):"
  797.          //             "%{static-libhwasan:"           "-Bstatic"                                              "} "
  798.          //             "-lhwasan "
  799.          //             "%{static-libhwasan:"           "-Bdynamic"                                             "} "
  800.          //             "%{static-libhwasan|static:"    "%:include(libsanitizer.spec)%(link_libhwasan)"         "}      "
  801.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=hwaddress"    "}"
  802.          //     "}    "
  803.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=hwaddress"))
  804.          {
  805.             if (ARGV_CONTAINS_SINGLEARG ("-static-libhwasan")) ADD_LINKER_ARG ("-Bstatic");
  806.             ADD_LINKER_ARG ("-lhwasan");
  807.             if (ARGV_CONTAINS_SINGLEARG ("-static-libhwasan")) ADD_LINKER_ARG ("-Bdynamic");
  808.             if (ARGV_CONTAINS_SINGLEARG ("-static-libhwasan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  809.                ADD_LINKER_ARG ("-lm"); // only known dependency to libhwasan on QNX
  810.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  811.             {
  812.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=hwaddress\n", argv[0]);
  813.                exit (1);
  814.             }
  815.          }
  816.  
  817.          //     "%{%:sanitize(thread):"
  818.          //             "%{static-libtsan:"             "-Bstatic"                                              "} "
  819.          //             "-ltsan "
  820.          //             "%{static-libtsan:"             "-Bdynamic"                                             "} "
  821.          //             "%{static-libtsan|static:"      "%:include(libsanitizer.spec)%(link_libtsan)"           "}    "
  822.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=thread"       "}"
  823.          //     "}    "
  824.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=thread"))
  825.          {
  826.             if (ARGV_CONTAINS_SINGLEARG ("-static-libtsan")) ADD_LINKER_ARG ("-Bstatic");
  827.             ADD_LINKER_ARG ("-ltsan");
  828.             if (ARGV_CONTAINS_SINGLEARG ("-static-libtsan")) ADD_LINKER_ARG ("-Bdynamic");
  829.             if (ARGV_CONTAINS_SINGLEARG ("-static-libtsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  830.                ADD_LINKER_ARG ("-lm"); // only known dependency to libtsan on QNX
  831.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  832.             {
  833.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=thread\n", argv[0]);
  834.                exit (1);
  835.             }
  836.          }
  837.  
  838.          //     "%{%:sanitize(undefined):"
  839.          //             "%{static-libubsan:"            "-Bstatic"                                              "} "
  840.          //             "-lubsan "
  841.          //             "%{static-libubsan:"            "-Bdynamic"                                             "} "
  842.          //             "%{static-libubsan|static:"     "%:include(libsanitizer.spec)%(link_libubsan)"          "}"
  843.          //     "}    "
  844.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=undefined"))
  845.          {
  846.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan")) ADD_LINKER_ARG ("-Bstatic");
  847.             ADD_LINKER_ARG ("-lubsan");
  848.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan")) ADD_LINKER_ARG ("-Bdynamic");
  849.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  850.                ADD_LINKER_ARG ("-lm"); // only known dependency to libubsan on QNX
  851.          }
  852.  
  853.          //     "%{%:sanitize(leak):"
  854.          //             "%{static-liblsan:"             "-Bstatic"                                              "} "
  855.          //             "-llsan "
  856.          //             "%{static-liblsan:"             "-Bdynamic"                                             "} "
  857.          //             "%{static-liblsan|static:"      "%:include(libsanitizer.spec)%(link_liblsan)"           "}"
  858.          //     "}"
  859.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=leak"))
  860.          {
  861.             if (ARGV_CONTAINS_SINGLEARG ("-static-liblsan")) ADD_LINKER_ARG ("-Bstatic");
  862.             ADD_LINKER_ARG ("-llsan");
  863.             if (ARGV_CONTAINS_SINGLEARG ("-static-liblsan")) ADD_LINKER_ARG ("-Bdynamic");
  864.             if (ARGV_CONTAINS_SINGLEARG ("-static-liblsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  865.                ADD_LINKER_ARG ("-lm"); // only known dependency to liblsan on QNX
  866.          }
  867. #else // !IS_TARGET_INTEL
  868.          //     "%{%:sanitize(address): "
  869.          //             "%{static-libasan|static:"      "%:include(libsanitizer.spec)%(link_libasan)"           "}    "
  870.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=address"      "}"
  871.          //     "}    "
  872.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=address"))
  873.          {
  874.             if (ARGV_CONTAINS_SINGLEARG ("-static-libasan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  875.                ADD_LINKER_ARG ("-lm"); // only known dependency to libasan on QNX
  876.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  877.             {
  878.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=address\n", argv[0]);
  879.                exit (1);
  880.             }
  881.          }
  882.  
  883.          //     "%{%:sanitize(hwaddress): "
  884.          //             "%{static-libhwasan|static:"    "%:include(libsanitizer.spec)%(link_libhwasan)"         "}      "
  885.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=hwaddress"    "}"
  886.          //     "}    "
  887.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=hwaddress"))
  888.          {
  889.             if (ARGV_CONTAINS_SINGLEARG ("-static-libhwasan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  890.                ADD_LINKER_ARG ("-lm"); // only known dependency to libhwasan on QNX
  891.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  892.             {
  893.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=hwaddress\n", argv[0]);
  894.                exit (1);
  895.             }
  896.          }
  897.  
  898.          //     "%{%:sanitize(thread): "
  899.          //             "%{static-libtsan|static:"      "%:include(libsanitizer.spec)%(link_libtsan)"           "}    "
  900.          //             "%{static:"                     "%ecannot specify -static with -fsanitize=thread"       "}"
  901.          //     "}    "
  902.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=thread"))
  903.          {
  904.             if (ARGV_CONTAINS_SINGLEARG ("-static-libtsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  905.                ADD_LINKER_ARG ("-lm"); // only known dependency to libtsan on QNX
  906.             if (ARGV_CONTAINS_SINGLEARG ("-static"))
  907.             {
  908.                fprintf (stderr, "%s: error: cannot specify -static with -fsanitize=thread\n", argv[0]);
  909.                exit (1);
  910.             }
  911.          }
  912.  
  913.          //     "%{%:sanitize(undefined):"
  914.          //             "%{static-libubsan:"            "-Bstatic"                                              "} "
  915.          //             "-lubsan "
  916.          //             "%{static-libubsan:"            "-Bdynamic"                                             "} "
  917.          //             "%{static-libubsan|static:"     "%:include(libsanitizer.spec)%(link_libubsan)"          "}"
  918.          //     "}    "
  919.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=undefined"))
  920.          {
  921.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan")) ADD_LINKER_ARG ("-Bstatic");
  922.             ADD_LINKER_ARG ("-lubsan");
  923.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan")) ADD_LINKER_ARG ("-Bdynamic");
  924.             if (ARGV_CONTAINS_SINGLEARG ("-static-libubsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  925.                ADD_LINKER_ARG ("-lm"); // only known dependency to libubsan on QNX
  926.          }
  927.  
  928.          //     "%{%:sanitize(leak): "
  929.          //             "%{static-liblsan|static:"      "%:include(libsanitizer.spec)%(link_liblsan)"           "}"
  930.          //     "}"
  931.          if (ARGV_CONTAINS_SINGLEARG ("-fsanitize=leak"))
  932.          {
  933.             if (ARGV_CONTAINS_SINGLEARG ("-static-liblsan") || ARGV_CONTAINS_SINGLEARG ("-static"))
  934.                ADD_LINKER_ARG ("-lm"); // only known dependency to liblsan on QNX
  935.          }
  936. #endif // IS_TARGET_INTEL
  937.  
  938.          // "%{fstack-protector|fstack-protector-all|fstack-protector-strong|fstack-protector-explicit:}"
  939.          // nothing to do
  940.  
  941.          // "%(link_gcc_c_sequence)"
  942. #if IS_TARGET_INTEL
  943.          //     "%{static|static-libgcc:"                       "-lgcc -lgcc_eh"        "}"
  944.          if (ARGV_CONTAINS_SINGLEARG ("-static") || ARGV_CONTAINS_SINGLEARG ("-static-libgcc"))
  945.          {
  946.             ADD_LINKER_ARG ("-lgcc");
  947.             ADD_LINKER_ARG ("-lgcc_eh");
  948.          }
  949.  
  950.          //     "%{!static:"
  951.          //             "%{!static-libgcc:"
  952.          //                     "%{!shared:"
  953.          //                             "%{!shared-libgcc:"     "-lgcc -lgcc_eh"        "}"
  954.          //                             "%{shared-libgcc:"      "-lgcc_s -lgcc"         "}"
  955.          //                     "}"
  956.          //                     "%{shared:"
  957.          //                             "%{shared-libgcc:"      "-lgcc_s"               "}"
  958.          //                             "%{!shared-libgcc:"     "-lgcc"                 "}"
  959.          //                     "}"
  960.          //             "}"
  961.          //     "}"
  962.          if (!ARGV_CONTAINS_SINGLEARG ("-static") && !ARGV_CONTAINS_SINGLEARG ("-static-libgcc"))
  963.          {
  964.             if (!ARGV_CONTAINS_SINGLEARG ("-shared"))
  965.             {
  966.                if (ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  967.                {
  968.                   ADD_LINKER_ARG ("-lgcc_s");
  969.                   ADD_LINKER_ARG ("-lgcc");
  970.                }
  971.                else
  972.                {
  973.                   ADD_LINKER_ARG ("-lgcc");
  974.                   ADD_LINKER_ARG ("-lgcc_eh");
  975.                }
  976.             }
  977.             else if (ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  978.                ADD_LINKER_ARG ("-lgcc_s");
  979.             else
  980.                ADD_LINKER_ARG ("-lgcc");
  981.          }
  982.  
  983.          //     "%{!nolibc:"
  984.          if (!ARGV_CONTAINS_SINGLEARG ("-nolibc"))
  985.          {
  986.             //  "%{!symbolic:"
  987.             //          " -lc"
  988.             //          " %{shared:"    "-lcS"  "}"
  989.             //          " %{!no-pie:"   "-lcS"  "}"
  990.             //          " %{no-pie:"    "-lc"   "}"
  991.             //  "} "
  992.             if (!ARGV_CONTAINS_SINGLEARG ("-symbolic"))
  993.             {
  994.                ADD_LINKER_ARG ("-lc");
  995.                if (ARGV_CONTAINS_SINGLEARG ("-shared") || !ARGV_CONTAINS_SINGLEARG ("-no-pie"))
  996.                   ADD_LINKER_ARG ("-lcS");
  997.             }
  998.  
  999.             //  "%{static|static-libgcc:"                       "-lgcc -lgcc_eh"        "}"
  1000.             if (ARGV_CONTAINS_SINGLEARG ("-static") || ARGV_CONTAINS_SINGLEARG ("-static-libgcc"))
  1001.             {
  1002.                ADD_LINKER_ARG ("-lgcc");
  1003.                ADD_LINKER_ARG ("-lgcc_eh");
  1004.             }
  1005.  
  1006.             //  "%{!static:"
  1007.             //          "%{!static-libgcc:"
  1008.             //                  "%{!shared:"
  1009.             //                          "%{!shared-libgcc:"     "-lgcc -lgcc_eh"        "}"
  1010.             //                          "%{shared-libgcc:"      "-lgcc_s -lgcc"         "}"
  1011.             //                  "}"
  1012.             //                  "%{shared:"
  1013.             //                          "%{shared-libgcc:"      "-lgcc_s"               "}"
  1014.             //                          "%{!shared-libgcc:"     "-lgcc"                 "}"
  1015.             //                  "}"
  1016.             //          "}"
  1017.             //  "
  1018.             if (!ARGV_CONTAINS_SINGLEARG ("-static") && !ARGV_CONTAINS_SINGLEARG ("-static-libgcc"))
  1019.             {
  1020.                if (!ARGV_CONTAINS_SINGLEARG ("-shared"))
  1021.                {
  1022.                   if (ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  1023.                   {
  1024.                      ADD_LINKER_ARG ("-lgcc_s");
  1025.                      ADD_LINKER_ARG ("-lgcc");
  1026.                   }
  1027.                   else
  1028.                   {
  1029.                      ADD_LINKER_ARG ("-lgcc");
  1030.                      ADD_LINKER_ARG ("-lgcc_eh");
  1031.                   }
  1032.                }
  1033.                else if (ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  1034.                   ADD_LINKER_ARG ("-lgcc_s");
  1035.                else
  1036.                   ADD_LINKER_ARG ("-lgcc");
  1037.             }
  1038.          }
  1039. #else // !IS_TARGET_INTEL
  1040.          //     "%{static|static-pie:"  "--start-group" "} "
  1041.          if (ARGV_CONTAINS_SINGLEARG ("-static") || ARGV_CONTAINS_SINGLEARG ("-static-pie"))
  1042.             ADD_LINKER_ARG ("--start-group");
  1043.  
  1044.          //     "%{static|static-libgcc|static-pie:"            "-lgcc -lgcc_eh"        "}"
  1045.          if (ARGV_CONTAINS_SINGLEARG ("-static") || ARGV_CONTAINS_SINGLEARG ("-static-libgcc") || ARGV_CONTAINS_SINGLEARG ("-static-pie"))
  1046.          {
  1047.             ADD_LINKER_ARG ("-lgcc");
  1048.             ADD_LINKER_ARG ("-lgcc_eh");
  1049.          }
  1050.  
  1051.          //     "%{!static:"
  1052.          //             "%{!static-libgcc:"
  1053.          //                     "%{!static-pie:"
  1054.          //                             "%{!shared-libgcc:"     "-lgcc --push-state --as-needed -lgcc_s --pop-state"    "}"
  1055.          //                             "%{shared-libgcc:"      "-lgcc_s%{!shared: -lgcc}"                              "}"
  1056.          //                     "}"
  1057.          //             "}"
  1058.          //     "}"
  1059.          if (!ARGV_CONTAINS_SINGLEARG ("-static") && !ARGV_CONTAINS_SINGLEARG ("-static-libgcc") && !ARGV_CONTAINS_SINGLEARG ("-static-pie"))
  1060.          {
  1061.             if (!ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  1062.             {
  1063.                ADD_LINKER_ARG ("-lgcc");
  1064.                ADD_LINKER_ARG ("--push-state");
  1065.                ADD_LINKER_ARG ("--as-needed");
  1066.                ADD_LINKER_ARG ("-lgcc_s");
  1067.                ADD_LINKER_ARG ("--pop-state");
  1068.             }
  1069.             else
  1070.             {
  1071.                ADD_LINKER_ARG ("-lgcc_s");
  1072.                if (!ARGV_CONTAINS_SINGLEARG ("-shared"))
  1073.                   ADD_LINKER_ARG ("-lgcc");
  1074.             }
  1075.          }
  1076.  
  1077.          //     "%{!nolibc:"
  1078.          //             "%{!symbolic:"
  1079.          //                     " -lc"
  1080.          //                     " %{shared:"    "-lcS"  "}"
  1081.          //                     " %{!no-pie:"   "-lcS"  "}"
  1082.          //                     " %{no-pie:"    "-lc"   "}"
  1083.          //             "} "
  1084.          // "}    "
  1085.          if (!ARGV_CONTAINS_SINGLEARG ("-nolibc") && !ARGV_CONTAINS_SINGLEARG ("-symbolic"))
  1086.          {
  1087.             ADD_LINKER_ARG ("-lc");
  1088.             if (ARGV_CONTAINS_SINGLEARG ("-shared") || !ARGV_CONTAINS_SINGLEARG ("-no-pie"))
  1089.                ADD_LINKER_ARG ("-lcS");
  1090.          }
  1091.  
  1092.          //     "%{static|static-pie:"  "--end-group"   "}"
  1093.          if (ARGV_CONTAINS_SINGLEARG ("-static") || ARGV_CONTAINS_SINGLEARG ("-static-pie"))
  1094.             ADD_LINKER_ARG ("--end-group");
  1095.          //     "%{!static:"
  1096.          //             "%{!static-pie:"
  1097.          else
  1098.          {
  1099.             //  "%{static|static-libgcc|static-pie:"            "-lgcc -lgcc_eh"        "}"
  1100.             if (ARGV_CONTAINS_SINGLEARG ("-static-libgcc"))
  1101.             {
  1102.                ADD_LINKER_ARG ("-lgcc");
  1103.                ADD_LINKER_ARG ("-lgcc_eh");
  1104.             }
  1105.  
  1106.             //  "%{!static:"
  1107.             //          "%{!static-libgcc:"
  1108.             //                  "%{!static-pie:"
  1109.             //                          "%{!shared-libgcc:"     "-lgcc --push-state --as-needed -lgcc_s --pop-state"    "}"
  1110.             //                          "%{shared-libgcc:"      "-lgcc_s%{!shared: -lgcc}"                              "}"
  1111.             //                  "}"
  1112.             //          "}"
  1113.             //  "}"
  1114.             if (!ARGV_CONTAINS_SINGLEARG ("-static") && !ARGV_CONTAINS_SINGLEARG ("-static-libgcc") && !ARGV_CONTAINS_SINGLEARG ("-static-pie"))
  1115.             {
  1116.                if (!ARGV_CONTAINS_SINGLEARG ("-shared-libgcc"))
  1117.                {
  1118.                   ADD_LINKER_ARG ("-lgcc");
  1119.                   ADD_LINKER_ARG ("--push-state");
  1120.                   ADD_LINKER_ARG ("--as-needed");
  1121.                   ADD_LINKER_ARG ("-lgcc_s");
  1122.                   ADD_LINKER_ARG ("--pop-state");
  1123.                }
  1124.                else
  1125.                {
  1126.                   ADD_LINKER_ARG ("-lgcc_s");
  1127.                   if (!ARGV_CONTAINS_SINGLEARG ("-shared"))
  1128.                      ADD_LINKER_ARG ("-lgcc");
  1129.                }
  1130.             }
  1131.          }
  1132. #endif // IS_TARGET_INTEL
  1133.  
  1134.          was_cpluspluslib_included = false;
  1135.          for (arg_index = 0; arg_index < larg_count; arg_index++)
  1136.          {
  1137.             ADD_LINKER_ARG (largs[arg_index]);
  1138.             if (((arg = strstr (largs[arg_index], "c++")) != NULL) && (arg[3] == 0))
  1139.                was_cpluspluslib_included = true; // catches -lstdc++ and -lc++
  1140.          }
  1141.          if (!was_cpluspluslib_included)
  1142.          {
  1143.             if (strstr (argv[0], "g++") != NULL)
  1144.                ADD_LINKER_ARG ("-lc++"); // if clang invoked us as g++ to link stuff it probably means we need a C++ library
  1145.             else
  1146.             {
  1147.                requires_libcplusplus = false; // figure it out the hard way: if we see a C++ mangled symbol name in one of the object files, it means we need a C++ library
  1148.                for (arg_index = 0; !requires_libcplusplus && (arg_index < oarg_count); arg_index++)
  1149.                {
  1150.                   fp = fopen (oargs[arg_index], "rb");
  1151.                   if (fp == NULL) continue; // unopenable object file, should error out perhaps?
  1152.                   while (!requires_libcplusplus && ((read_count = fread (filebuf, 1, sizeof (filebuf), fp)) > 0))
  1153.                      for (byte_index = 0; !requires_libcplusplus && (byte_index < read_count - 8); byte_index++)
  1154.                         if (memcmp (&filebuf[byte_index], ".text._Z", 8) == 0)
  1155.                            requires_libcplusplus = true;
  1156.                   fclose (fp);
  1157.                }
  1158.                if (requires_libcplusplus)
  1159.                   ADD_LINKER_ARG ("-lc++"); // we did it the hard way
  1160.             }
  1161.          }
  1162.       }
  1163.  
  1164.       //        "%{!nostartfiles:"      "%E"                                    "}"
  1165.       if (!ARGV_CONTAINS_SINGLEARG ("-nostartfiles"))
  1166.       {
  1167.          ADD_LINKER_ARG (resolve_envvars ("${QNX_HOST}/usr/bin/../lib/gcc/" TARGET_TRIPLE "/" BASEVER "/crtend.o"));
  1168. #if IS_TARGET_INTEL
  1169.          if (ARGV_CONTAINS_SINGLEARG ("-m32"))
  1170.             ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86/lib/crtn.o"));
  1171.          else
  1172.             ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/x86_64/lib/crtn.o"));
  1173. #else // !IS_TARGET_INTEL
  1174.          if (ARGV_CONTAINS_SINGLEARG ("-EB"))
  1175.             ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64be/lib/crtn.o"));
  1176.          else
  1177.             ADD_LINKER_ARG (resolve_envvars ("${QNX_TARGET}/aarch64le/lib/crtn.o"));
  1178. #endif // IS_TARGET_INTEL
  1179.       }
  1180.    }
  1181.  
  1182.    //   "%{T*}"
  1183.    for (arg_index = 1; arg_index < argc; arg_index++)
  1184.       if ((strcmp (argv[arg_index], "-T") == 0) && (arg_index + 1 < argc))
  1185.       {
  1186.          ADD_LINKER_ARG ("-T");
  1187.          ADD_LINKER_ARG (argv[++arg_index]);
  1188.       }
  1189.       else if ((strncmp (argv[arg_index], "-T", 2) == 0) && ((argv[arg_index])[2] != 0))
  1190.          ADD_LINKER_ARG (argv[arg_index]);
  1191.  
  1192.    if (ARGV_CONTAINS_SINGLEARG ("-v") || (getenv ("DEBUG_LINKER_DRIVER") != NULL))
  1193.    {
  1194.       fputs ("LINKER DRIVER: CONSTRUCTED COMMAND LINE BEGIN\n", stderr);
  1195.       for (arg_index = 0; arg_index < linker_argc; arg_index++)
  1196.          fprintf (stderr, "%s%s%s\n", (arg_index > 0 ? "\t" : ""), linker_argv[arg_index], ((size_t) arg_index + 1 < linker_argc ? " \\" : ""));
  1197.       fputs ("LINKER DRIVER: CONSTRUCTED COMMAND LINE END\n", stderr);
  1198.    }
  1199.  
  1200.    execvpe (LINKER, linker_argv, envp);
  1201.    return (1); // unreachable code
  1202. }
  1203.