Subversion Repositories QNX 8.QNX8 linker driver

Rev

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