Commit | Line | Data |
---|---|---|
5f8ac7e7 SC |
1 | # This shell script emits a C file. -*- C -*- |
2 | # It does some substitutions. | |
3 | cat >e${EMULATION_NAME}.c <<EOF | |
5f8ac7e7 | 4 | /* This file is part of GLD, the Gnu Linker. |
3535c3c0 | 5 | Copyright 1995, 96, 97, 1998 Free Software Foundation, Inc. |
5f8ac7e7 SC |
6 | |
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
20 | ||
3535c3c0 NC |
21 | /* For WINDOWS_NT */ |
22 | /* The original file generated returned different default scripts depending | |
23 | on whether certain switches were set, but these switches pertain to the | |
24 | Linux system and that particular version of coff. In the NT case, we | |
25 | only determine if the subsystem is console or windows in order to select | |
26 | the correct entry point by default. */ | |
27 | ||
5f8ac7e7 SC |
28 | #include "bfd.h" |
29 | #include "sysdep.h" | |
30 | #include "bfdlink.h" | |
31 | #include "getopt.h" | |
3535c3c0 | 32 | #include "libiberty.h" |
5f8ac7e7 SC |
33 | #include "ld.h" |
34 | #include "ldmain.h" | |
35 | #include "ldgram.h" | |
36 | #include "ldexp.h" | |
37 | #include "ldlang.h" | |
38 | #include "ldemul.h" | |
39 | #include "ldlex.h" | |
40 | #include "ldmisc.h" | |
41 | #include "ldctor.h" | |
42 | #include "ldfile.h" | |
43 | #include "coff/internal.h" | |
44 | #include "../bfd/libcoff.h" | |
45 | ||
d4279937 SC |
46 | #define TARGET_IS_${EMULATION_NAME} |
47 | ||
fe6e2957 DE |
48 | static void gld_${EMULATION_NAME}_set_symbols PARAMS ((void)); |
49 | static void gld_${EMULATION_NAME}_after_open PARAMS ((void)); | |
5f8ac7e7 | 50 | static void gld_${EMULATION_NAME}_before_parse PARAMS ((void)); |
5b6ca067 | 51 | static void gld_${EMULATION_NAME}_after_parse PARAMS ((void)); |
fe6e2957 | 52 | static void gld_${EMULATION_NAME}_before_allocation PARAMS ((void)); |
5b6ca067 | 53 | static boolean gld_${EMULATION_NAME}_place_orphan |
a1613b5f | 54 | PARAMS ((lang_input_statement_type *, asection *)); |
7617a822 ILT |
55 | static void gld${EMULATION_NAME}_place_section |
56 | PARAMS ((lang_statement_union_type *)); | |
fe6e2957 DE |
57 | static char *gld_${EMULATION_NAME}_get_script PARAMS ((int *)); |
58 | static int gld_${EMULATION_NAME}_parse_args PARAMS ((int, char **)); | |
59 | ||
5f8ac7e7 SC |
60 | static struct internal_extra_pe_aouthdr pe; |
61 | static int dll; | |
5b6ca067 | 62 | static int support_old_code = 0; |
5f8ac7e7 | 63 | |
3535c3c0 NC |
64 | extern const char *output_filename; |
65 | ||
5f8ac7e7 SC |
66 | static void |
67 | gld_${EMULATION_NAME}_before_parse() | |
68 | { | |
3535c3c0 | 69 | output_filename = "a.exe"; |
5f8ac7e7 SC |
70 | ldfile_output_architecture = bfd_arch_${ARCH}; |
71 | } | |
fe6e2957 DE |
72 | \f |
73 | /* PE format extra command line options. */ | |
5f8ac7e7 SC |
74 | |
75 | /* Used for setting flags in the PE header. */ | |
76 | #define OPTION_BASE_FILE (300 + 1) | |
77 | #define OPTION_DLL (OPTION_BASE_FILE + 1) | |
78 | #define OPTION_FILE_ALIGNMENT (OPTION_DLL + 1) | |
79 | #define OPTION_IMAGE_BASE (OPTION_FILE_ALIGNMENT + 1) | |
80 | #define OPTION_MAJOR_IMAGE_VERSION (OPTION_IMAGE_BASE + 1) | |
81 | #define OPTION_MAJOR_OS_VERSION (OPTION_MAJOR_IMAGE_VERSION + 1) | |
82 | #define OPTION_MAJOR_SUBSYSTEM_VERSION (OPTION_MAJOR_OS_VERSION + 1) | |
83 | #define OPTION_MINOR_IMAGE_VERSION (OPTION_MAJOR_SUBSYSTEM_VERSION + 1) | |
84 | #define OPTION_MINOR_OS_VERSION (OPTION_MINOR_IMAGE_VERSION + 1) | |
85 | #define OPTION_MINOR_SUBSYSTEM_VERSION (OPTION_MINOR_OS_VERSION + 1) | |
86 | #define OPTION_SECTION_ALIGNMENT (OPTION_MINOR_SUBSYSTEM_VERSION + 1) | |
87 | #define OPTION_STACK (OPTION_SECTION_ALIGNMENT + 1) | |
88 | #define OPTION_SUBSYSTEM (OPTION_STACK + 1) | |
89 | #define OPTION_HEAP (OPTION_SUBSYSTEM + 1) | |
5b6ca067 | 90 | #define OPTION_SUPPORT_OLD_CODE (OPTION_HEAP + 1) |
5f8ac7e7 | 91 | |
5b6ca067 ILT |
92 | static struct option longopts[] = |
93 | { | |
5f8ac7e7 | 94 | /* PE options */ |
5b6ca067 ILT |
95 | {"base-file", required_argument, NULL, OPTION_BASE_FILE}, |
96 | {"dll", no_argument, NULL, OPTION_DLL}, | |
97 | {"file-alignment", required_argument, NULL, OPTION_FILE_ALIGNMENT}, | |
98 | {"heap", required_argument, NULL, OPTION_HEAP}, | |
99 | {"image-base", required_argument, NULL, OPTION_IMAGE_BASE}, | |
100 | {"major-image-version", required_argument, NULL, OPTION_MAJOR_IMAGE_VERSION}, | |
101 | {"major-os-version", required_argument, NULL, OPTION_MAJOR_OS_VERSION}, | |
102 | {"major-subsystem-version", required_argument, NULL, OPTION_MAJOR_SUBSYSTEM_VERSION}, | |
103 | {"minor-image-version", required_argument, NULL, OPTION_MINOR_IMAGE_VERSION}, | |
104 | {"minor-os-version", required_argument, NULL, OPTION_MINOR_OS_VERSION}, | |
105 | {"minor-subsystem-version", required_argument, NULL, OPTION_MINOR_SUBSYSTEM_VERSION}, | |
106 | {"section-alignment", required_argument, NULL, OPTION_SECTION_ALIGNMENT}, | |
107 | {"stack", required_argument, NULL, OPTION_STACK}, | |
108 | {"subsystem", required_argument, NULL, OPTION_SUBSYSTEM}, | |
109 | {"support-old-code", no_argument, NULL, OPTION_SUPPORT_OLD_CODE}, | |
110 | {NULL, no_argument, NULL, 0} | |
111 | }; | |
5f8ac7e7 SC |
112 | |
113 | ||
114 | /* PE/WIN32; added routines to get the subsystem type, heap and/or stack | |
115 | parameters which may be input from the command line */ | |
116 | ||
5b6ca067 ILT |
117 | typedef struct |
118 | { | |
5f8ac7e7 SC |
119 | void *ptr; |
120 | int size; | |
121 | int value; | |
122 | char *symbol; | |
123 | int inited; | |
124 | } definfo; | |
125 | ||
126 | #define D(field,symbol,def) {&pe.field,sizeof(pe.field), def, symbol,0} | |
127 | ||
128 | static definfo init[] = | |
129 | { | |
130 | /* imagebase must be first */ | |
131 | #define IMAGEBASEOFF 0 | |
132 | D(ImageBase,"__image_base__", NT_EXE_IMAGE_BASE), | |
133 | #define DLLOFF 1 | |
134 | {&dll, sizeof(dll), 0, "__dll__"}, | |
135 | D(SectionAlignment,"__section_alignment__", PE_DEF_SECTION_ALIGNMENT), | |
136 | D(FileAlignment,"__file_alignment__", PE_DEF_FILE_ALIGNMENT), | |
137 | D(MajorOperatingSystemVersion,"__major_os_version__", 4), | |
138 | D(MinorOperatingSystemVersion,"__minor_os_version__", 0), | |
139 | D(MajorImageVersion,"__major_image_version__", 1), | |
140 | D(MinorImageVersion,"__minor_image_version__", 0), | |
141 | D(MajorSubsystemVersion,"__major_subsystem_version__", 4), | |
142 | D(MinorSubsystemVersion,"__minor_subsystem_version__", 0), | |
143 | D(Subsystem,"__subsystem__", 3), | |
417fe276 | 144 | D(SizeOfStackReserve,"__size_of_stack_reserve__", 0x2000000), |
5f8ac7e7 SC |
145 | D(SizeOfStackCommit,"__size_of_stack_commit__", 0x1000), |
146 | D(SizeOfHeapReserve,"__size_of_heap_reserve__", 0x100000), | |
147 | D(SizeOfHeapCommit,"__size_of_heap_commit__", 0x1000), | |
148 | D(LoaderFlags,"__loader_flags__", 0x0), | |
3535c3c0 | 149 | { NULL, 0, 0, NULL, 0 } |
5f8ac7e7 SC |
150 | }; |
151 | ||
5b6ca067 ILT |
152 | static void |
153 | gld_${EMULATION_NAME}_list_options (file) | |
154 | FILE * file; | |
155 | { | |
156 | fprintf (file, _(" --base_file <basefile> Generate a base file for relocatable DLLs\n")); | |
157 | fprintf (file, _(" --dll Set image base to the default for DLLs\n")); | |
158 | fprintf (file, _(" --file-alignment <size> Set file alignment\n")); | |
159 | fprintf (file, _(" --heap <size> Set initial size of the heap\n")); | |
160 | fprintf (file, _(" --image-base <address> Set start address of the executable\n")); | |
161 | fprintf (file, _(" --major-image-version <number> Set version number of the executable\n")); | |
162 | fprintf (file, _(" --major-os-version <number> Set minimum required OS version\n")); | |
163 | fprintf (file, _(" --major-subsystem-version <number> Set minimum required OS subsystem version\n")); | |
164 | fprintf (file, _(" --minor-image-version <number> Set revision number of the executable\n")); | |
165 | fprintf (file, _(" --minor-os-version <number> Set minimum required OS revision\n")); | |
166 | fprintf (file, _(" --minor-subsystem-version <number> Set minimum required OS subsystem revision\n")); | |
167 | fprintf (file, _(" --section-alignment <size> Set section alignment\n")); | |
168 | fprintf (file, _(" --stack <size> Set size of the initial stack\n")); | |
169 | fprintf (file, _(" --subsystem <name>[:<version>] Set required OS subsystem [& version]\n")); | |
170 | fprintf (file, _(" --support-old-code Support interworking with old code\n")); | |
171 | } | |
5f8ac7e7 SC |
172 | |
173 | static void | |
174 | set_pe_name (name, val) | |
175 | char *name; | |
176 | long val; | |
177 | { | |
178 | int i; | |
179 | /* Find the name and set it. */ | |
180 | for (i = 0; init[i].ptr; i++) | |
181 | { | |
182 | if (strcmp (name, init[i].symbol) == 0) | |
183 | { | |
184 | init[i].value = val; | |
185 | init[i].inited = 1; | |
186 | return; | |
187 | } | |
188 | } | |
189 | abort(); | |
190 | } | |
191 | ||
192 | ||
193 | static void | |
194 | set_pe_subsystem () | |
195 | { | |
3535c3c0 NC |
196 | const char *sver; |
197 | int len; | |
5f8ac7e7 | 198 | int i; |
3535c3c0 | 199 | static const struct |
5f8ac7e7 | 200 | { |
3535c3c0 NC |
201 | const char *name; |
202 | const int value; | |
203 | const char *entry; | |
5f8ac7e7 SC |
204 | } |
205 | v[] = | |
206 | { | |
3535c3c0 NC |
207 | { "native", 1, "_NtProcessStartup" }, |
208 | { "windows", 2, "_WinMainCRTStartup" }, | |
209 | { "console", 3, "_mainCRTStartup" }, | |
210 | #if 0 | |
211 | /* The Microsoft linker does not recognize this. */ | |
212 | { "os2", 5, "" }, | |
213 | #endif | |
214 | { "posix", 7, "___PosixProcessStartup"}, | |
215 | { 0, 0, 0 } | |
5f8ac7e7 SC |
216 | }; |
217 | ||
3535c3c0 NC |
218 | sver = strchr (optarg, ':'); |
219 | if (sver == NULL) | |
220 | len = strlen (optarg); | |
221 | else | |
222 | { | |
223 | char *end; | |
224 | ||
225 | len = sver - optarg; | |
226 | set_pe_name ("__major_subsystem_version__", | |
227 | strtoul (sver + 1, &end, 0)); | |
228 | if (*end == '.') | |
229 | set_pe_name ("__minor_subsystem_version__", | |
230 | strtoul (end + 1, &end, 0)); | |
231 | if (*end != '\0') | |
5b6ca067 | 232 | einfo (_("%P: warning: bad version number in -subsystem option\n")); |
3535c3c0 NC |
233 | } |
234 | ||
5f8ac7e7 SC |
235 | for (i = 0; v[i].name; i++) |
236 | { | |
3535c3c0 NC |
237 | if (strncmp (optarg, v[i].name, len) == 0 |
238 | && v[i].name[len] == '\0') | |
5f8ac7e7 SC |
239 | { |
240 | set_pe_name ("__subsystem__", v[i].value); | |
d0d63887 | 241 | |
3535c3c0 | 242 | lang_add_entry (v[i].entry, 1); |
d0d63887 | 243 | |
5f8ac7e7 SC |
244 | return; |
245 | } | |
246 | } | |
5b6ca067 ILT |
247 | |
248 | einfo (_("%P%F: invalid subsystem type %s\n"), optarg); | |
5f8ac7e7 SC |
249 | } |
250 | ||
251 | ||
252 | ||
253 | static void | |
254 | set_pe_value (name) | |
255 | char *name; | |
256 | ||
257 | { | |
258 | char *end; | |
5b6ca067 | 259 | |
fe6e2957 | 260 | set_pe_name (name, strtoul (optarg, &end, 0)); |
5b6ca067 | 261 | |
5f8ac7e7 | 262 | if (end == optarg) |
5b6ca067 | 263 | einfo (_("%P%F: invalid hex number for PE parameter '%s'\n"), optarg); |
5f8ac7e7 SC |
264 | |
265 | optarg = end; | |
266 | } | |
267 | ||
268 | static void | |
269 | set_pe_stack_heap (resname, comname) | |
270 | char *resname; | |
271 | char *comname; | |
272 | { | |
5f8ac7e7 | 273 | set_pe_value (resname); |
5b6ca067 | 274 | |
5f8ac7e7 SC |
275 | if (*optarg == ',') |
276 | { | |
277 | optarg++; | |
278 | set_pe_value (comname); | |
279 | } | |
280 | else if (*optarg) | |
5b6ca067 | 281 | einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg); |
5f8ac7e7 SC |
282 | } |
283 | ||
284 | ||
285 | ||
286 | static int | |
287 | gld_${EMULATION_NAME}_parse_args(argc, argv) | |
288 | int argc; | |
289 | char **argv; | |
290 | { | |
291 | int longind; | |
292 | int optc; | |
293 | int prevoptind = optind; | |
294 | int prevopterr = opterr; | |
2543860d SC |
295 | int wanterror; |
296 | static int lastoptind = -1; | |
297 | ||
298 | if (lastoptind != optind) | |
299 | opterr = 0; | |
300 | wanterror = opterr; | |
301 | ||
302 | lastoptind = optind; | |
303 | ||
5f8ac7e7 SC |
304 | optc = getopt_long_only (argc, argv, "-", longopts, &longind); |
305 | opterr = prevopterr; | |
2543860d | 306 | |
5f8ac7e7 SC |
307 | switch (optc) |
308 | { | |
309 | default: | |
2543860d SC |
310 | if (wanterror) |
311 | xexit (1); | |
312 | optind = prevoptind; | |
5f8ac7e7 SC |
313 | return 0; |
314 | ||
315 | case OPTION_BASE_FILE: | |
d4279937 | 316 | link_info.base_file = (PTR) fopen (optarg, FOPEN_WB); |
5f8ac7e7 SC |
317 | if (link_info.base_file == NULL) |
318 | { | |
5b6ca067 ILT |
319 | /* xgettext:c-format */ |
320 | fprintf (stderr, _("%s: Can't open base file %s\n"), | |
5f8ac7e7 SC |
321 | program_name, optarg); |
322 | xexit (1); | |
323 | } | |
324 | break; | |
325 | ||
326 | /* PE options */ | |
327 | case OPTION_HEAP: | |
a1613b5f | 328 | set_pe_stack_heap ("__size_of_heap_reserve__", "__size_of_heap_commit__"); |
5f8ac7e7 SC |
329 | break; |
330 | case OPTION_STACK: | |
a1613b5f | 331 | set_pe_stack_heap ("__size_of_stack_reserve__", "__size_of_stack_commit__"); |
5f8ac7e7 SC |
332 | break; |
333 | case OPTION_SUBSYSTEM: | |
334 | set_pe_subsystem (); | |
335 | break; | |
336 | case OPTION_MAJOR_OS_VERSION: | |
337 | set_pe_value ("__major_os_version__"); | |
338 | break; | |
339 | case OPTION_MINOR_OS_VERSION: | |
340 | set_pe_value ("__minor_os_version__"); | |
341 | break; | |
342 | case OPTION_MAJOR_SUBSYSTEM_VERSION: | |
343 | set_pe_value ("__major_subsystem_version__"); | |
344 | break; | |
345 | case OPTION_MINOR_SUBSYSTEM_VERSION: | |
2543860d | 346 | set_pe_value ("__minor_subsystem_version__"); |
5f8ac7e7 SC |
347 | break; |
348 | case OPTION_MAJOR_IMAGE_VERSION: | |
349 | set_pe_value ("__major_image_version__"); | |
350 | break; | |
351 | case OPTION_MINOR_IMAGE_VERSION: | |
352 | set_pe_value ("__minor_image_version__"); | |
353 | break; | |
354 | case OPTION_FILE_ALIGNMENT: | |
355 | set_pe_value ("__file_alignment__"); | |
356 | break; | |
357 | case OPTION_SECTION_ALIGNMENT: | |
358 | set_pe_value ("__section_alignment__"); | |
359 | break; | |
360 | case OPTION_DLL: | |
361 | set_pe_name ("__dll__", 1); | |
362 | break; | |
363 | case OPTION_IMAGE_BASE: | |
364 | set_pe_value ("__image_base__"); | |
365 | break; | |
5b6ca067 ILT |
366 | case OPTION_SUPPORT_OLD_CODE: |
367 | support_old_code = 1; | |
368 | break; | |
5f8ac7e7 SC |
369 | } |
370 | return 1; | |
371 | } | |
fe6e2957 | 372 | \f |
3535c3c0 NC |
373 | /* Assign values to the special symbols before the linker script is |
374 | read. */ | |
375 | ||
5f8ac7e7 | 376 | static void |
5b6ca067 | 377 | gld_${EMULATION_NAME}_set_symbols () |
5f8ac7e7 | 378 | { |
5f8ac7e7 SC |
379 | /* Run through and invent symbols for all the |
380 | names and insert the defaults. */ | |
381 | int j; | |
2543860d | 382 | lang_statement_list_type *save; |
5f8ac7e7 SC |
383 | |
384 | if (!init[IMAGEBASEOFF].inited) | |
3535c3c0 NC |
385 | { |
386 | if (link_info.relocateable) | |
387 | init[IMAGEBASEOFF].value = 0; | |
388 | else if (init[DLLOFF].value) | |
389 | init[IMAGEBASEOFF].value = NT_DLL_IMAGE_BASE; | |
390 | else | |
391 | init[IMAGEBASEOFF].value = NT_EXE_IMAGE_BASE; | |
392 | } | |
393 | ||
394 | /* Don't do any symbol assignments if this is a relocateable link. */ | |
395 | if (link_info.relocateable) | |
396 | return; | |
5f8ac7e7 | 397 | |
2543860d | 398 | /* Glue the assignments into the abs section */ |
d4279937 | 399 | save = stat_ptr; |
2543860d SC |
400 | |
401 | stat_ptr = &(abs_output_section->children); | |
d4279937 | 402 | |
5f8ac7e7 SC |
403 | for (j = 0; init[j].ptr; j++) |
404 | { | |
405 | long val = init[j].value; | |
406 | lang_add_assignment (exp_assop ('=' ,init[j].symbol, exp_intop (val))); | |
407 | if (init[j].size == sizeof(short)) | |
408 | *(short *)init[j].ptr = val; | |
409 | else if (init[j].size == sizeof(int)) | |
410 | *(int *)init[j].ptr = val; | |
411 | else if (init[j].size == sizeof(long)) | |
412 | *(long *)init[j].ptr = val; | |
3535c3c0 NC |
413 | /* This might be a long long or other special type. */ |
414 | else if (init[j].size == sizeof(bfd_vma)) | |
415 | *(bfd_vma *)init[j].ptr = val; | |
5f8ac7e7 SC |
416 | else abort(); |
417 | } | |
2543860d SC |
418 | /* Restore the pointer. */ |
419 | stat_ptr = save; | |
420 | ||
5f8ac7e7 SC |
421 | if (pe.FileAlignment > |
422 | pe.SectionAlignment) | |
423 | { | |
5b6ca067 | 424 | einfo (_("%P: warning, file alignment > section alignment.\n")); |
5f8ac7e7 SC |
425 | } |
426 | } | |
427 | ||
5b6ca067 ILT |
428 | /* This is called after the linker script and the command line options |
429 | have been read. */ | |
430 | ||
431 | static void | |
432 | gld_${EMULATION_NAME}_after_parse () | |
433 | { | |
434 | /* The Windows libraries are designed for the linker to treat the | |
435 | entry point as an undefined symbol. Otherwise, the .obj that | |
436 | defines mainCRTStartup is brought in because it is the first | |
437 | encountered in libc.lib and it has other symbols in it which will | |
438 | be pulled in by the link process. To avoid this, we act as | |
439 | though the user specified -u with the entry point symbol. | |
440 | ||
441 | This function is called after the linker script and command line | |
442 | options have been read, so at this point we know the right entry | |
443 | point. This function is called before the input files are | |
444 | opened, so registering the symbol as undefined will make a | |
445 | difference. */ | |
446 | ||
447 | ldlang_add_undef (entry_symbol); | |
448 | } | |
449 | ||
5f8ac7e7 | 450 | static void |
5b6ca067 | 451 | gld_${EMULATION_NAME}_after_open () |
5f8ac7e7 | 452 | { |
3535c3c0 NC |
453 | /* Pass the wacky PE command line options into the output bfd. |
454 | FIXME: This should be done via a function, rather than by | |
455 | including an internal BFD header. */ | |
5b6ca067 ILT |
456 | |
457 | if (!coff_data (output_bfd)->pe) | |
458 | einfo (_("%F%P: PE operations on non PE file.\n")); | |
5f8ac7e7 | 459 | |
5b6ca067 ILT |
460 | pe_data (output_bfd)->pe_opthdr = pe; |
461 | pe_data (output_bfd)->dll = init[DLLOFF].value; | |
5f8ac7e7 | 462 | |
5b6ca067 ILT |
463 | #ifdef TARGET_IS_armpe |
464 | { | |
465 | /* Find a BFD that can hold the interworking stubs. */ | |
466 | LANG_FOR_EACH_INPUT_STATEMENT (is) | |
467 | { | |
468 | if (bfd_arm_get_bfd_for_interworking (is->the_bfd, & link_info)) | |
469 | break; | |
470 | } | |
471 | } | |
472 | #endif | |
5f8ac7e7 | 473 | } |
a1613b5f | 474 | \f |
5f8ac7e7 SC |
475 | static void |
476 | gld_${EMULATION_NAME}_before_allocation() | |
477 | { | |
d4279937 SC |
478 | #ifdef TARGET_IS_ppcpe |
479 | /* Here we rummage through the found bfds to collect toc information */ | |
480 | { | |
481 | LANG_FOR_EACH_INPUT_STATEMENT (is) | |
482 | { | |
5b6ca067 | 483 | if (!ppc_process_before_allocation (is->the_bfd, &link_info)) |
417fe276 | 484 | { |
5b6ca067 ILT |
485 | /* xgettext:c-format */ |
486 | einfo (_("Errors encountered processing file %s\n"), is->filename); | |
417fe276 | 487 | } |
d4279937 SC |
488 | } |
489 | } | |
490 | ||
491 | /* We have seen it all. Allocate it, and carry on */ | |
492 | ppc_allocate_toc_section (&link_info); | |
5b6ca067 ILT |
493 | #endif /* TARGET_IS_ppcpe */ |
494 | ||
495 | #ifdef TARGET_IS_armpe | |
496 | /* FIXME: we should be able to set the size of the interworking stub | |
497 | section. | |
498 | ||
499 | Here we rummage through the found bfds to collect glue | |
500 | information. FIXME: should this be based on a command line | |
501 | option? krk@cygnus.com */ | |
3535c3c0 NC |
502 | { |
503 | LANG_FOR_EACH_INPUT_STATEMENT (is) | |
504 | { | |
5b6ca067 ILT |
505 | if (! bfd_arm_process_before_allocation |
506 | (is->the_bfd, & link_info, support_old_code)) | |
3535c3c0 | 507 | { |
5b6ca067 ILT |
508 | /* xgettext:c-format */ |
509 | einfo (_("Errors encountered processing file %s for interworking"), | |
510 | is->filename); | |
3535c3c0 NC |
511 | } |
512 | } | |
513 | } | |
514 | ||
515 | /* We have seen it all. Allocate it, and carry on */ | |
5b6ca067 ILT |
516 | bfd_arm_allocate_interworking_sections (& link_info); |
517 | #endif /* TARGET_IS_armpe */ | |
5f8ac7e7 | 518 | } |
a1613b5f | 519 | \f |
7617a822 ILT |
520 | /* Place an orphan section. |
521 | ||
522 | We use this to put sections in a reasonable place in the file, and | |
523 | to ensure that they are aligned as required. | |
524 | ||
525 | We handle grouped sections here as well. A section named .foo$nn | |
526 | goes into the output section .foo. All grouped sections are sorted | |
527 | by name. | |
3535c3c0 | 528 | |
7617a822 ILT |
529 | Grouped sections for the default sections are handled by the |
530 | default linker script using wildcards, and are sorted by | |
531 | sort_sections. */ | |
532 | ||
533 | static asection *hold_section; | |
534 | static char *hold_section_name; | |
535 | static lang_output_section_statement_type *hold_use; | |
536 | static lang_output_section_statement_type *hold_text; | |
537 | static lang_output_section_statement_type *hold_rdata; | |
538 | static lang_output_section_statement_type *hold_data; | |
539 | static lang_output_section_statement_type *hold_bss; | |
540 | ||
541 | /* Place an orphan section. We use this to put random SHF_ALLOC | |
542 | sections in the right segment. */ | |
a1613b5f DE |
543 | |
544 | /*ARGSUSED*/ | |
545 | static boolean | |
5b6ca067 | 546 | gld_${EMULATION_NAME}_place_orphan (file, s) |
a1613b5f DE |
547 | lang_input_statement_type *file; |
548 | asection *s; | |
549 | { | |
fe6e2957 | 550 | const char *secname; |
7617a822 | 551 | char *dollar; |
a1613b5f DE |
552 | |
553 | if ((s->flags & SEC_ALLOC) == 0) | |
554 | return false; | |
555 | ||
a1613b5f DE |
556 | secname = bfd_get_section_name (s->owner, s); |
557 | ||
7617a822 ILT |
558 | /* Look through the script to see where to place this section. */ |
559 | ||
560 | hold_section = s; | |
561 | ||
562 | hold_section_name = xstrdup (secname); | |
563 | dollar = strchr (hold_section_name, '$'); | |
564 | if (dollar != NULL) | |
565 | *dollar = '\0'; | |
566 | ||
567 | hold_use = NULL; | |
568 | lang_for_each_statement (gld${EMULATION_NAME}_place_section); | |
a1613b5f | 569 | |
7617a822 | 570 | if (hold_use == NULL) |
a1613b5f | 571 | { |
7617a822 ILT |
572 | lang_output_section_statement_type *place; |
573 | char *outsecname; | |
574 | asection *snew, **pps; | |
575 | lang_statement_list_type *old; | |
576 | lang_statement_list_type add; | |
577 | etree_type *address; | |
578 | ||
579 | /* Try to put the new output section in a reasonable place based | |
580 | on the section name and section flags. */ | |
581 | place = NULL; | |
582 | if ((s->flags & SEC_HAS_CONTENTS) == 0 | |
583 | && hold_bss != NULL) | |
584 | place = hold_bss; | |
585 | else if ((s->flags & SEC_READONLY) == 0 | |
586 | && hold_data != NULL) | |
587 | place = hold_data; | |
588 | else if ((s->flags & SEC_CODE) == 0 | |
589 | && (s->flags & SEC_READONLY) != 0 | |
590 | && hold_rdata != NULL) | |
591 | place = hold_rdata; | |
592 | else if ((s->flags & SEC_READONLY) != 0 | |
593 | && hold_text != NULL) | |
594 | place = hold_text; | |
595 | ||
596 | /* Choose a unique name for the section. This will be needed if | |
597 | the same section name appears in the input file with | |
598 | different loadable or allocateable characteristics. */ | |
599 | outsecname = xstrdup (hold_section_name); | |
600 | if (bfd_get_section_by_name (output_bfd, outsecname) != NULL) | |
601 | { | |
602 | unsigned int len; | |
603 | char *newname; | |
604 | unsigned int i; | |
605 | ||
606 | len = strlen (outsecname); | |
607 | newname = xmalloc (len + 5); | |
608 | strcpy (newname, outsecname); | |
609 | i = 0; | |
610 | do | |
611 | { | |
612 | sprintf (newname + len, "%d", i); | |
613 | ++i; | |
614 | } | |
615 | while (bfd_get_section_by_name (output_bfd, newname) != NULL); | |
616 | ||
617 | free (outsecname); | |
618 | outsecname = newname; | |
619 | } | |
620 | ||
621 | /* We don't want to free OUTSECNAME, as it may get attached to | |
622 | the output section statement. */ | |
623 | ||
624 | /* Create the section in the output file, and put it in the | |
625 | right place. This shuffling is to make the output file look | |
626 | neater. */ | |
627 | snew = bfd_make_section (output_bfd, outsecname); | |
628 | if (snew == NULL) | |
629 | einfo ("%P%F: output format %s cannot represent section called %s\n", | |
630 | output_bfd->xvec->name, outsecname); | |
631 | if (place != NULL && place->bfd_section != NULL) | |
632 | { | |
633 | for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) | |
634 | ; | |
635 | *pps = snew->next; | |
636 | snew->next = place->bfd_section->next; | |
637 | place->bfd_section->next = snew; | |
638 | } | |
639 | ||
640 | /* Start building a list of statements for this section. */ | |
641 | old = stat_ptr; | |
642 | stat_ptr = &add; | |
643 | lang_list_init (stat_ptr); | |
644 | ||
645 | if (link_info.relocateable) | |
646 | address = NULL; | |
647 | else | |
648 | { | |
649 | /* All sections in an executable must be aligned to a page | |
650 | boundary. */ | |
651 | address = exp_unop (ALIGN_K, | |
652 | exp_nameop (NAME, "__section_alignment__")); | |
653 | } | |
654 | ||
655 | lang_enter_output_section_statement (outsecname, address, 0, | |
656 | (bfd_vma) 0, | |
657 | (etree_type *) NULL, | |
658 | (etree_type *) NULL, | |
659 | (etree_type *) NULL); | |
660 | ||
661 | hold_use = lang_output_section_statement_lookup (outsecname); | |
662 | ||
663 | lang_leave_output_section_statement | |
664 | ((bfd_vma) 0, "*default*", | |
665 | (struct lang_output_section_phdr_list *) NULL); | |
666 | ||
667 | /* Now stick the new statement list right after PLACE. */ | |
668 | if (place != NULL) | |
669 | { | |
670 | *add.tail = place->header.next; | |
671 | place->header.next = add.head; | |
672 | } | |
673 | ||
674 | stat_ptr = old; | |
a1613b5f | 675 | } |
7617a822 ILT |
676 | |
677 | if (dollar == NULL) | |
678 | wild_doit (&hold_use->children, s, hold_use, file); | |
679 | else | |
a1613b5f | 680 | { |
7617a822 ILT |
681 | lang_statement_union_type **pl; |
682 | boolean found_dollar; | |
683 | lang_statement_list_type list; | |
684 | ||
685 | /* The section name has a '$'. Sort it with the other '$' | |
686 | sections. */ | |
687 | ||
688 | found_dollar = false; | |
689 | for (pl = &hold_use->children.head; *pl != NULL; pl = &(*pl)->next) | |
690 | { | |
691 | lang_input_section_type *ls; | |
692 | const char *lname; | |
693 | ||
694 | if ((*pl)->header.type != lang_input_section_enum) | |
695 | continue; | |
696 | ||
697 | ls = &(*pl)->input_section; | |
698 | ||
699 | lname = bfd_get_section_name (ls->ifile->the_bfd, ls->section); | |
700 | if (strchr (lname, '$') == NULL) | |
701 | { | |
702 | if (found_dollar) | |
703 | break; | |
704 | } | |
705 | else | |
706 | { | |
707 | found_dollar = true; | |
708 | if (strcmp (secname, lname) < 0) | |
709 | break; | |
710 | } | |
711 | } | |
712 | ||
713 | lang_list_init (&list); | |
714 | wild_doit (&list, s, hold_use, file); | |
715 | ASSERT (list.head != NULL && list.head->next == NULL); | |
716 | ||
717 | list.head->next = *pl; | |
718 | *pl = list.head; | |
a1613b5f | 719 | } |
a1613b5f | 720 | |
7617a822 | 721 | free (hold_section_name); |
a1613b5f DE |
722 | |
723 | return true; | |
724 | } | |
7617a822 ILT |
725 | |
726 | static void | |
727 | gld${EMULATION_NAME}_place_section (s) | |
728 | lang_statement_union_type *s; | |
729 | { | |
730 | lang_output_section_statement_type *os; | |
731 | ||
732 | if (s->header.type != lang_output_section_statement_enum) | |
733 | return; | |
734 | ||
735 | os = &s->output_section_statement; | |
736 | ||
737 | if (strcmp (os->name, hold_section_name) == 0 | |
738 | && os->bfd_section != NULL | |
739 | && ((hold_section->flags & (SEC_LOAD | SEC_ALLOC)) | |
740 | == (os->bfd_section->flags & (SEC_LOAD | SEC_ALLOC)))) | |
741 | hold_use = os; | |
742 | ||
743 | if (strcmp (os->name, ".text") == 0) | |
744 | hold_text = os; | |
745 | else if (strcmp (os->name, ".rdata") == 0) | |
746 | hold_rdata = os; | |
747 | else if (strcmp (os->name, ".data") == 0) | |
748 | hold_data = os; | |
749 | else if (strcmp (os->name, ".bss") == 0) | |
750 | hold_bss = os; | |
751 | } | |
a1613b5f | 752 | \f |
5f8ac7e7 SC |
753 | static char * |
754 | gld_${EMULATION_NAME}_get_script(isfile) | |
755 | int *isfile; | |
756 | EOF | |
757 | # Scripts compiled in. | |
758 | # sed commands to quote an ld script as a C string. | |
759 | sc="-f ${srcdir}/emultempl/stringify.sed" | |
760 | ||
761 | cat >>e${EMULATION_NAME}.c <<EOF | |
762 | { | |
763 | *isfile = 0; | |
764 | ||
765 | if (link_info.relocateable == true && config.build_constructors == true) | |
766 | return | |
767 | EOF | |
768 | sed $sc ldscripts/${EMULATION_NAME}.xu >> e${EMULATION_NAME}.c | |
769 | echo ' ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}.c | |
770 | sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c | |
771 | echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c | |
772 | sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c | |
773 | echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c | |
774 | sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c | |
775 | echo ' ; else return' >> e${EMULATION_NAME}.c | |
776 | sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c | |
777 | echo '; }' >> e${EMULATION_NAME}.c | |
778 | ||
779 | cat >>e${EMULATION_NAME}.c <<EOF | |
780 | ||
781 | ||
5f8ac7e7 SC |
782 | struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = |
783 | { | |
784 | gld_${EMULATION_NAME}_before_parse, | |
785 | syslib_default, | |
786 | hll_default, | |
5b6ca067 | 787 | gld_${EMULATION_NAME}_after_parse, |
5f8ac7e7 SC |
788 | gld_${EMULATION_NAME}_after_open, |
789 | after_allocation_default, | |
790 | set_output_arch_default, | |
791 | ldemul_default_target, | |
792 | gld_${EMULATION_NAME}_before_allocation, | |
793 | gld_${EMULATION_NAME}_get_script, | |
794 | "${EMULATION_NAME}", | |
795 | "${OUTPUT_FORMAT}", | |
796 | NULL, /* finish */ | |
797 | NULL, /* create output section statements */ | |
798 | NULL, /* open dynamic archive */ | |
5b6ca067 | 799 | gld_${EMULATION_NAME}_place_orphan, |
5f8ac7e7 | 800 | gld_${EMULATION_NAME}_set_symbols, |
5b6ca067 ILT |
801 | gld_${EMULATION_NAME}_parse_args, |
802 | NULL, /* unrecognised file */ | |
803 | gld_${EMULATION_NAME}_list_options | |
5f8ac7e7 SC |
804 | }; |
805 | EOF |