Subversion Repositories QNX 8.QNX8 linker driver

Rev

Rev 8 | Rev 11 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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