Subversion Repositories QNX 8.QNX8 linker driver

Rev

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

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