1 /* special.c: Routines to handle special characteristics of the linker
2
3 Copyright (C) 2002-2004 Sebastian Reichelt
4 Copyright (C) 2003-2005 Kevin Kofler
5 Copyright (C) 2004 Billy Charvet
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, or (at your option)
10 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 Foundation,
19 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20
21 #include "special.h"
22
23 #include "integers.h"
24 #include "manip.h"
25 #include "insert/insert.h"
26
27 #include <string.h>
28 #include <stdlib.h>
29
30 // Try to translate an external symbol into a special-feature symbol used by the linker.
31 // If the symbol contains a number, it is written to the variable pointed to by Number.
TranslateSpecialExternalSymbol(PROGRAM * Program,char * SymbolName,void ** Reference,OFFSET * Number)32 SpecialExternalSymbolTypes TranslateSpecialExternalSymbol (PROGRAM *Program, char *SymbolName, void **Reference, OFFSET *Number)
33 {
34 SpecialExternalSymbolTypes SymType = ST_NORMAL;
35 char *SymNum = SymbolName, *Divider = NULL;
36 int NumBase = 16;
37
38 if (!(strncmp (SymbolName, "tiamsapi_", sizeof ("tiamsapi_") - 1)))
39 {
40 SymType = ST_ROM_CALL;
41 SymNum += sizeof ("tiamsapi_") - 1;
42 NumBase = 10;
43 }
44 if (!(strncmp (SymbolName, "_ROM_CALL_", sizeof ("_ROM_CALL_") - 1)))
45 {
46 SymType = ST_ROM_CALL;
47 SymNum += sizeof ("_ROM_CALL_") - 1;
48 }
49 else if (!(strncmp (SymbolName, "_RAM_CALL_", sizeof ("_RAM_CALL_") - 1)))
50 {
51 SymType = ST_RAM_CALL;
52 SymNum += sizeof ("_RAM_CALL_") - 1;
53 }
54 else if (!(strncmp (SymbolName, "_extraramaddr@", sizeof ("_extraramaddr@") - 1)))
55 {
56 SymType = ST_EXTRA_RAM;
57 SymNum += sizeof ("_extraramaddr@") - 1;
58 }
59 else if (!(strncmp (SymbolName, "_extraramaddr__", sizeof ("_extraramaddr__") - 1)))
60 {
61 SymType = ST_EXTRA_RAM;
62 SymNum += sizeof ("_extraramaddr__") - 1;
63 }
64 else if (((Divider = strchr (SymbolName, '@'))) || (((Divider = strstr (SymbolName, "__"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
65 {
66 if (*Divider == '@')
67 SymNum = Divider + 1;
68 else
69 SymNum = Divider + 2;
70 if (strlen (SymNum) == 4)
71 SymType = ST_LIB_CALL;
72 }
73
74 if (SymType != ST_NORMAL)
75 {
76 // Get the number the symbol contains (in hex).
77 if (Number)
78 {
79 char *Err;
80 *Number = strtoul (SymNum, &Err, NumBase);
81 // If the number has an error in it, revert to normal symbol.
82 if (*Err)
83 SymType = ST_NORMAL;
84 }
85 }
86
87 if (SymType == ST_LIB_CALL)
88 {
89 // Cut SymbolName at the divider.
90 *Divider = 0;
91 // Get a reference to the library identified by SymbolName.
92 if (Reference)
93 {
94 *Reference = GetLibrary (Program, SymbolName);
95 if (!(*Reference))
96 SymType = ST_NORMAL;
97 }
98 }
99
100 return SymType;
101 }
102
103 // Handle the symbol if it is a special one.
104 // Returns TRUE if it was special; in this case it should not be used.
HandleSpecialSymbol(PROGRAM * Program,const char * SymbolName)105 BOOLEAN HandleSpecialSymbol (PROGRAM *Program, const char *SymbolName)
106 {
107 BOOLEAN SymbolNameMatches (const char *Name)
108 {
109 return (!(strcmp (SymbolName, Name)));
110 }
111
112 const char *Divider;
113
114 // All special symbols start with an underscore.
115 if (SymbolName [0] == '_')
116 {
117 SymbolName++;
118
119 // The most important special symbol: __ref_all_xxx.
120 // It adds xxx to the global imports.
121 if (!(strncmp (SymbolName, "_ref_all_", sizeof ("_ref_all_") - 1)))
122 {
123 if (!(Program->IgnoreGlobalImports))
124 AddGlobalImport (Program, SymbolName + sizeof ("_ref_all_") - 1);
125 }
126 else if (SymbolNameMatches ("tigcc_native"))
127 {
128 // Kernel is the default type. Everything else must be defined explicitly
129 // and should therefore take precedence over _tigcc_native.
130 if (Program->Type == PT_KERNEL)
131 Program->Type = PT_NATIVE;
132 }
133 else if (SymbolNameMatches ("nostub"))
134 {
135 SECTION *FirstSection = GetFirst (Program->Sections);
136 if (FirstSection && (!(FirstSection->StartupNumber)))
137 FirstSection->Essential = TRUE;
138 Program->Type = PT_NOSTUB;
139 }
140 #ifdef NOSTUB_DLL_SUPPORT
141 else if (SymbolNameMatches ("nostub_dll"))
142 {
143 SECTION *FirstSection = GetFirst (Program->Sections);
144 if (FirstSection && (!(FirstSection->StartupNumber)))
145 FirstSection->Essential = TRUE;
146 Program->Type = PT_NOSTUB_DLL;
147 Program->Library = TRUE;
148 }
149 #endif /* NOSTUB_DLL_SUPPORT */
150 #ifdef FARGO_SUPPORT
151 else if (SymbolNameMatches ("fargo"))
152 Program->Type = PT_FARGO;
153 #endif /* FARGO_SUPPORT */
154 #ifdef FLASH_OS_SUPPORT
155 else if (SymbolNameMatches ("flash_os"))
156 Program->Type = PT_FLASH_OS;
157 #endif /* FLASH_OS_SUPPORT */
158 else if (SymbolNameMatches ("library"))
159 {
160 Program->Library = TRUE;
161 #ifdef FARGO_SUPPORT
162 // Under Fargo, _library is a normal symbol as well.
163 if (Program->Type == PT_FARGO)
164 return FALSE;
165 #endif /* FARGO_SUPPORT */
166 }
167 else if (SymbolNameMatches ("ti92"))
168 {
169 Program->Calcs |= CALC_TI92;
170 }
171 else if (SymbolNameMatches ("ti89"))
172 {
173 Program->Calcs |= CALC_TI89;
174 Program->KernelFlags |= 0x02;
175 }
176 else if (SymbolNameMatches ("ti89ti"))
177 {
178 Program->Calcs |= CALC_TI89 | CALC_FLAG_TITANIUM;
179 Program->KernelFlags |= 0x42;
180 }
181 else if (SymbolNameMatches ("ti92plus"))
182 {
183 Program->Calcs |= CALC_TI92PLUS;
184 Program->KernelFlags |= 0x01;
185 }
186 else if (SymbolNameMatches ("v200"))
187 {
188 Program->Calcs |= CALC_V200;
189 Program->KernelFlags |= 0x20;
190 }
191 else if (!(strncmp (SymbolName, "flag_", sizeof ("flag_") - 1)))
192 Program->KernelFlags |= (1 << strtoul (SymbolName + sizeof ("flag_") - 1, NULL, 10));
193 else if (!(strncmp (SymbolName, "version", sizeof ("version") - 1)))
194 Program->Version = strtoul (SymbolName + sizeof ("version") - 1, NULL, 16);
195 else if (!(strcmp (SymbolName, "_ld_use_fline_jumps")))
196 {
197 if (Program->OptimizeInfo)
198 Program->OptimizeInfo->UseFLineJumps = TRUE;
199 }
200 else if (!(strcmp (SymbolName, "_ld_use_4byte_fline_jumps")))
201 {
202 if (Program->OptimizeInfo)
203 Program->OptimizeInfo->Use4ByteFLineJumps = TRUE;
204 }
205 else if (!(strcmp (SymbolName, SYM_IGNORE_GLOBAL_IMPORTS + 1)))
206 Program->IgnoreGlobalImports = TRUE;
207 else if (SymbolNameMatches (SYM_OMIT_BSS_INIT + 1) || SymbolNameMatches (SYM_ALL_RELOCS + 1))
208 // These are mostly file-local special symbols; they are handled
209 // by the importing function.
210 ;
211 else
212 // Not a special symbol.
213 return FALSE;
214
215 // The symbol was handled here.
216 return TRUE;
217 }
218 else if (((Divider = strstr (SymbolName, "@version"))) || (((Divider = strstr (SymbolName, "__version"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
219 {
220 // Required minimum version number for a library.
221 const char *Version;
222 VERSION VersionNumber;
223
224 if (*Divider == '@')
225 Version = Divider + sizeof ("@version") - 1;
226 else
227 Version = Divider + sizeof ("__version") - 1;
228 VersionNumber = strtoul (Version, NULL, 16);
229
230 if (VersionNumber)
231 {
232 if (Divider - SymbolName <= MAX_SYM_LEN)
233 {
234 char LibName[MAX_SYM_LEN+1];
235 LIBRARY *Library;
236
237 strncpy (LibName, SymbolName, Divider - SymbolName);
238 LibName [Divider - SymbolName] = 0;
239 Library = GetLibrary (Program, LibName);
240 if (Library && (Library->Version < VersionNumber))
241 Library->Version = VersionNumber;
242 }
243
244 return TRUE;
245 }
246 }
247
248 return FALSE;
249 }
250
251 // Translate a section name into a startup section number.
252 // Returns 0 if the name does not represent a startup section.
GetStartupSectionNumber(const char * SectionName,SIZE MaxLen)253 OFFSET GetStartupSectionNumber (const char *SectionName, SIZE MaxLen)
254 {
255 // Check if it looks like a startup section.
256 if ((MaxLen > (SIZE) (sizeof ("_st") - 1)) && (!(strncmp (SectionName, "_st", sizeof ("_st") - 1))))
257 {
258 // Copy the section name to a temporary null-terminated location.
259 char SecName[MaxLen+1];
260 memset (SecName, 0, MaxLen + 1);
261 strncpy (SecName, SectionName, MaxLen);
262 // Check whether it is a library startup section.
263 if (SecName [sizeof ("_st") - 1] == 'l')
264 {
265 // Library startup sections are special:
266 // They may always be included, even if the file is not executable.
267 // Therefore they get a negative number to distinguish them.
268 OFFSET RealNum = strtoul (SecName + sizeof ("_stl") - 1, NULL, 10);
269 return (RealNum ? RealNum - 10000 : 0);
270 }
271 else
272 return (strtoul (SecName + sizeof ("_st") - 1, NULL, 10));
273 }
274 else
275 return 0;
276 }
277
278 // Translate a symbol name into the number of an exported function, if the
279 // function is meant to be exported.
280 // Returns -1 if it is not an exported function.
GetExportNumber(const char * SymbolName)281 OFFSET GetExportNumber (const char *SymbolName)
282 {
283 const char *Divider;
284
285 if (((Divider = strchr (SymbolName, '@'))) || (((Divider = strstr (SymbolName, "__"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
286 {
287 OFFSET Number;
288 char *Err;
289
290 if (*Divider == '@')
291 Divider++;
292 else
293 Divider += 2;
294
295 Number = strtoul (Divider, &Err, 16);
296 if (*Err)
297 return (-1);
298
299 return Number;
300 }
301 else
302 return (-1);
303 }
304
305 // Add all imports with names defined by this program, if they are needed.
CreateSpecialGlobalImports(PROGRAM * Program)306 BOOLEAN CreateSpecialGlobalImports (PROGRAM *Program)
307 {
308 BOOLEAN Result = TRUE;
309 SECTION *TempSection;
310
311 if (Program->Type == PT_KERNEL)
312 {
313 if (Program->Library)
314 Result = Result && AddGlobalImport (Program, "__kernel_library_header");
315 else
316 Result = Result && AddGlobalImport (Program, "__kernel_program_header");
317 }
318 #ifdef FARGO_SUPPORT
319 else if (Program->Type == PT_FARGO)
320 {
321 if (Program->Library)
322 Result = Result && AddGlobalImport (Program, "__fargo_library_header");
323 else
324 Result = Result && AddGlobalImport (Program, "__fargo_program_header");
325 }
326 #endif /* FARGO_SUPPORT */
327 #ifdef FLASH_OS_SUPPORT
328 else if (Program->Type == PT_FLASH_OS)
329 Result = Result && AddGlobalImport (Program, "__flash_os_header");
330 #endif /* FLASH_OS_SUPPORT */
331 if (Program->Constructors.Start)
332 Result = Result && AddGlobalImport (Program, "__handle_constructors");
333 if (Program->Destructors.Start)
334 Result = Result && AddGlobalImport (Program, "__handle_destructors");
335 if (Program->BSSSection && Program->BSSSection->Initialized)
336 Result = Result && AddGlobalImport (Program, "__initialize_bss");
337
338 // Handle BSS section if any.
339 if (Program->BSSSection && (!(Program->BSSSection->Handled)))
340 {
341 GLOBAL_IMPORT *Import = CreateGlobalImport (Program, "__handle_bss");
342 if (Import)
343 {
344 // This is the import that will mark the BSS section as handled
345 // if it succeeds.
346 Program->BSSImport = Import;
347
348 // Try to resolve it against available archives.
349 ResolveGlobalImport (Program, Import);
350
351 // The BSS section is simply merged into the rest if it is not
352 // handled.
353 Import->Succeeded = TRUE;
354 }
355 else
356 Result = FALSE;
357 }
358
359 // Handle absolute relocs if there are any.
360 for_each (TempSection, Program->Sections)
361 {
362 BOOLEAN Done = FALSE;
363 RELOC *TempReloc;
364 for_each (TempReloc, TempSection->Relocs)
365 {
366 if ((!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled)))))
367 {
368 GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_relocs");
369 if (Import)
370 // Relocs are either handled by the export format, or a
371 // warning is emitted.
372 Import->Succeeded = TRUE;
373 else
374 Result = FALSE;
375 Done = TRUE;
376 break;
377 }
378 }
379 if (Done)
380 break;
381 }
382
383 // Handle ROM calls if there are any.
384 for_each (TempSection, Program->Sections)
385 {
386 if (!(IsEmpty (TempSection->ROMCalls)))
387 {
388 GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_rom_calls");
389 if (Import)
390 // ROM calls are either handled by the export format, or a
391 // warning is emitted.
392 Import->Succeeded = TRUE;
393 else
394 Result = FALSE;
395 break;
396 }
397 }
398
399 // Handle RAM calls if there are any.
400 for_each (TempSection, Program->Sections)
401 {
402 if (!(IsEmpty (TempSection->RAMCalls)))
403 {
404 GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_ram_calls");
405 if (Import)
406 // RAM calls are either handled by the export format, or a
407 // warning is emitted.
408 Import->Succeeded = TRUE;
409 else
410 Result = FALSE;
411 break;
412 }
413 }
414
415 // Handle libraries if any libraries are referenced.
416 if (!(IsEmpty (Program->Libraries)))
417 {
418 GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_libraries");
419 if (Import)
420 // Libraries are either handled by the export format, or a
421 // warning is emitted.
422 Import->Succeeded = TRUE;
423 else
424 Result = FALSE;
425 }
426
427 // Handle _nostub comments if any.
428 if ((Program->Type == PT_NATIVE) || (Program->Type == PT_NOSTUB))
429 {
430 BOOLEAN NostubComments = FALSE;
431 for_each (TempSection, Program->Sections)
432 {
433 SYMBOL *TempSymbol;
434 for_each (TempSymbol, TempSection->Symbols)
435 {
436 if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, "_nostub_data__", sizeof ("_nostub_data__") - 1))))
437 {
438 OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + sizeof ("_nostub_") - 1);
439 if (ExportNumber >= 0)
440 {
441 NostubComments = TRUE;
442 TempSection->Essential = TRUE;
443 break;
444 }
445 }
446 }
447 }
448 if (NostubComments)
449 Result = Result && AddGlobalImport (Program, "__nostub_comment_header");
450 }
451
452 #ifdef DATA_VAR_SUPPORT
453 // Handle data variable if desired.
454 if (Program->DataVarInfo->Name && Program->DataSection)
455 {
456 Result = Result && (AddGlobalImport (Program, "__handle_data_var"));
457 if (Program->DataVarInfo->CreateCopy)
458 {
459 Result = Result && (AddGlobalImport (Program, "__data_var_create_copy"));
460 if (Program->DataVarInfo->CopyOnlyIfArchived)
461 Result = Result && (AddGlobalImport (Program, "__data_var_copy_if_archived"));
462 }
463 }
464 #endif /* DATA_VAR_SUPPORT */
465
466 return Result;
467 }
468
469 // If the reloc or its relation point to a special ld-exported symbol,
470 // change it to the appropriate value if possible. FALSE is returned
471 // only if it is not a special symbol location, or if there was an error.
ResolveSpecialSymbolReloc(RELOC * Reloc,BOOLEAN * TryAgain)472 BOOLEAN ResolveSpecialSymbolReloc (RELOC *Reloc, BOOLEAN *TryAgain)
473 {
474 // At first, resolve the relation, because if this is a built-in
475 // number, we cannot write it into the section contents directly,
476 // but we have to subtract it from FixedOffset.
477 BOOLEAN Result = ResolveSpecialSymbolRelocRelation (Reloc, TryAgain);
478
479 // Now resolve the target.
480 return (ResolveSpecialSymbolRelocTarget (Reloc, TryAgain) ? Result : FALSE);
481 }
482
483 // If the reloc points to a special ld-exported symbol, change it to the
484 // appropriate value if possible. FALSE is returned only if it is not a
485 // special symbol reloc, or if there was an error.
ResolveSpecialSymbolRelocTarget(RELOC * Reloc,BOOLEAN * TryAgain)486 BOOLEAN ResolveSpecialSymbolRelocTarget (RELOC *Reloc, BOOLEAN *TryAgain)
487 {
488 BOOLEAN Result = FALSE;
489 SECTION *Section = Reloc->Parent;
490 LOCATION *Location = &(Reloc->Target);
491
492 // If the relation is an unresolved reference to a builtin number,
493 // do not even try to resolve the target. This would only cause
494 // trouble, since we would need to handle it immediately if it
495 // resolved to a number. There will be another call to this anyway
496 // after the relation has finally been resolved.
497 // Usually, we would at least need to set the Target.Builtin flag.
498 // However, currently all tests which check for Target.Builtin also
499 // check for Relation or Relative in general. If this ever changes,
500 // this code will break.
501 if (Reloc->Relation && Reloc->Relation->Builtin)
502 return TRUE;
503
504 if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
505 {
506 // If it has resolved to a number, write it into the section
507 // contents.
508 if (!(Location->Symbol || Location->SymbolName))
509 {
510 if (Reloc->Relation)
511 Warning (GetFileName (Section, Reloc->Location), "Ignoring invalid negative reference to `%s' at 0x%lX.", Reloc->Relation->SymbolName, (long) Reloc->Location);
512
513 if ((Reloc->Location >= 0) && (Reloc->Location + Reloc->Size <= Section->Size))
514 {
515 // Add the target offset (to support things such as "__ld_xxx+1").
516 OFFSET NewValue = Location->Offset + Reloc->FixedOffset;
517
518 if (Reloc->Relative)
519 Warning (GetFileName (Section, Reloc->Location), "Invalid relative reference to built-in number `%s' at 0x%lX; changing to absolute.", Reloc->Target.SymbolName, (long) Reloc->Location);
520
521 // Check if the section contents at the reloc are zero.
522 if (!(IsZeroDataRange (Section, Reloc->Location, Reloc->Location + Reloc->Size)))
523 Warning (GetFileName (Section, Reloc->Location), "Builtin reloc at 0x%lX to `%s' on nonzero section contents. Overlapping with another?", (long) Reloc->Location, Reloc->Target.SymbolName);
524
525 // Resolve the reloc by writing the value into the section.
526 Result = AddTI (Section->Data + Reloc->Location, Reloc->Size, NewValue, TRUE, TRUE);
527
528 if (!Result)
529 Error (GetFileName (Section, Reloc->Location), "Number `%s' (=%ld) too large for size %ld reloc at 0x%lX.", Reloc->Target.SymbolName, (long) NewValue, (long) Reloc->Size, (long) Reloc->Location);
530 }
531 else
532 {
533 Warning (GetFileName (Section, Reloc->Location), "Removing reloc at 0x%lX to `%s' outside of section.", (long) Reloc->Location, Reloc->Target.SymbolName);
534 Result = TRUE;
535 }
536
537 FreeReloc (Reloc);
538 }
539 else
540 Result = TRUE;
541 }
542
543 return Result;
544 }
545
546 // If the reloc's relation points to a special ld-exported symbol,
547 // change it to the appropriate value if possible. FALSE is returned
548 // only if it is not a special symbol location, or if there was an error.
ResolveSpecialSymbolRelocRelation(RELOC * Reloc,BOOLEAN * TryAgain)549 BOOLEAN ResolveSpecialSymbolRelocRelation (RELOC *Reloc, BOOLEAN *TryAgain)
550 {
551 BOOLEAN Result = FALSE;
552 SECTION *Section = Reloc->Parent;
553 LOCATION *Location = Reloc->Relation;
554
555 if (Reloc->Relation)
556 {
557 // Try to resolve the relation.
558 if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
559 {
560 // Check if it has really been resolved.
561 BOOLEAN Resolved = (Location->Symbol != NULL);
562
563 // If it has been resolved to a number, subtract it from
564 // FixedOffset.
565 if (!(Location->Symbol || Location->SymbolName))
566 {
567 Reloc->FixedOffset -= Location->Offset;
568 FreeRelocRelation (Reloc);
569 Resolved = TRUE;
570 }
571
572 Result = TRUE;
573 }
574 }
575
576 return Result;
577 }
578
579 // If the location points to a special ld-exported symbol, change it to the
580 // appropriate value if possible. FALSE is returned only if it is not a
581 // special symbol location, or if there was an error.
582 // Warning: If the special symbol resolves to a number, Location->Symbol and
583 // Location->SymbolName will both be NULL, and Location->Offset will contain
584 // the number.
ResolveSpecialSymbolLocation(SECTION * Section,LOCATION * Location,BOOLEAN * TryAgain)585 BOOLEAN ResolveSpecialSymbolLocation (SECTION *Section, LOCATION *Location, BOOLEAN *TryAgain)
586 {
587 const char *SymName = Location->SymbolName;
588
589 BOOLEAN SymNameMatches (const char *Name)
590 {
591 return (!(strcmp (SymName, Name)));
592 }
593
594 // Locations that are already resolved do not need any treatment.
595 if (Location->Symbol)
596 return FALSE;
597
598 // All special symbols start with '_'.
599 if (SymName && (SymName [0] == '_'))
600 {
601 PROGRAM *Program = Section->Parent;
602 BOOLEAN SetToEntryPoint = FALSE;
603 OFFSET NewValue = 0;
604
605 SymName++;
606
607 // All built-in symbols start with "__ld_".
608 if (!(strncmp (SymName, SYMPF_BUILTIN + 1, sizeof (SYMPF_BUILTIN) - 2)))
609 {
610 SIZE SymNameLength;
611 BOOLEAN HasValue = FALSE;
612 SYMBOL *NewSymbol = NULL;
613 OFFSET NewTargetOffset = 0;
614 SECTION *TempSection;
615
616 // Skip the "__ld_" prefix.
617 SymName += sizeof (SYMPF_BUILTIN) - 2;
618 SymNameLength = strlen (SymName);
619
620 // Find (but do not resolve) calculator constants.
621 if (IsCalcBuiltinLocation (Location))
622 ;
623 // Resolve references to insertions.
624 else if (!(strncmp (SymName, SYMPF_INSERT, sizeof (SYMPF_INSERT) - 1)))
625 {
626 if ((!(TempSection = Program->MainSection))
627 || (!(NewSymbol = HandleAutoInsertion (TempSection, Location->SymbolName))))
628 return TRUE;
629 }
630 // Resolve "has_...s".
631 else if ((!(strncmp (SymName, "has_", sizeof ("has_") - 1))) && (SymName [SymNameLength - 1] == 's'))
632 {
633 if (Program->ResolveAllBuiltins)
634 {
635 Program->Frozen = TRUE;
636 if (GetBuiltinValue (Program, SymName + (sizeof ("has_") - 1), SymNameLength - 1 - (sizeof ("has_") - 1), &NewValue, -1))
637 HasValue = TRUE;
638 }
639 }
640 // Resolve "..._count".
641 else if ((SymNameLength > ((SIZE) (sizeof ("_count") - 1))) && (!(strcmp (SymName + SymNameLength - (sizeof ("_count") - 1), "_count"))))
642 {
643 if (Program->ResolveAllBuiltins)
644 {
645 Program->Frozen = TRUE;
646 if (GetBuiltinValue (Program, SymName, SymNameLength - (sizeof ("_count") - 1), &NewValue, 0))
647 HasValue = TRUE;
648 }
649 }
650 else if (SymNameMatches ("entry_point"))
651 SetToEntryPoint = TRUE;
652 else if (SymNameMatches ("entry_point_plus_0x8000"))
653 {
654 SetToEntryPoint = TRUE;
655 NewValue = 0x8000;
656 }
657 else if (SymNameMatches ("constructors_start"))
658 {
659 if (!(NewSymbol = Program->Constructors.Start))
660 return TRUE;
661 }
662 else if (SymNameMatches ("constructors_end"))
663 {
664 if (!(NewSymbol = Program->Constructors.End))
665 return TRUE;
666 }
667 else if (SymNameMatches ("constructors_size"))
668 {
669 if (Program->Constructors.Start && Program->Constructors.End)
670 {
671 NewValue = Program->Constructors.End->Location - Program->Constructors.Start->Location;
672 HasValue = TRUE;
673 }
674 else if (Program->ResolveAllBuiltins)
675 HasValue = TRUE;
676 }
677 else if (SymNameMatches ("destructors_start"))
678 {
679 if (!(NewSymbol = Program->Destructors.Start))
680 return TRUE;
681 }
682 else if (SymNameMatches ("destructors_end"))
683 {
684 if (!(NewSymbol = Program->Destructors.End))
685 return TRUE;
686 }
687 else if (SymNameMatches ("destructors_size"))
688 {
689 if (Program->Destructors.Start && Program->Destructors.End)
690 {
691 NewValue = Program->Destructors.End->Location - Program->Destructors.Start->Location;
692 HasValue = TRUE;
693 }
694 else if (Program->ResolveAllBuiltins)
695 HasValue = TRUE;
696 }
697 else if (SymNameMatches ("data_start"))
698 {
699 if (Program->DataSection)
700 NewSymbol = Program->DataSection->SectionSymbol;
701 else
702 return TRUE;
703 }
704 else if (SymNameMatches ("data_end"))
705 {
706 if (Program->DataSection)
707 {
708 NewSymbol = Program->DataSection->SectionSymbol;
709 NewTargetOffset = Program->DataSection->Size;
710 }
711 else
712 return TRUE;
713 }
714 else if (SymNameMatches ("data_size"))
715 {
716 if (Program->DataSection)
717 {
718 NewValue = Program->DataSection->Size;
719 HasValue = TRUE;
720 }
721 else if (Program->ResolveAllBuiltins)
722 HasValue = TRUE;
723 }
724 else if (SymNameMatches ("bss_start"))
725 {
726 if (Program->BSSSection)
727 NewSymbol = Program->BSSSection->SectionSymbol;
728 else
729 return TRUE;
730 }
731 else if (SymNameMatches ("bss_end"))
732 {
733 if (Program->BSSSection)
734 {
735 NewSymbol = Program->BSSSection->SectionSymbol;
736 NewTargetOffset = Program->BSSSection->Size;
737 }
738 else
739 return TRUE;
740 }
741 else if (SymNameMatches ("bss_size"))
742 {
743 if (Program->BSSSection)
744 {
745 NewValue = Program->BSSSection->Size;
746 HasValue = TRUE;
747 }
748 else if (Program->ResolveAllBuiltins)
749 HasValue = TRUE;
750 }
751 else if (SymNameMatches ("file_version"))
752 {
753 if (Program->ResolveAllBuiltins || Program->Version)
754 {
755 NewValue = Program->Version;
756 HasValue = TRUE;
757 }
758 }
759 else if (SymNameMatches ("kernel_flags"))
760 {
761 if (Program->ResolveAllBuiltins)
762 {
763 NewValue = Program->KernelFlags;
764 HasValue = TRUE;
765 }
766 }
767 else if (SymNameMatches ("kernel_bss_table"))
768 {
769 if (Program->BSSSection)
770 {
771 strcpy ((char *) (Location->SymbolName), "__kernel_bss_table");
772 if (TryAgain)
773 *TryAgain = TRUE;
774 // This prevents the section from being merged, and prevents
775 // relocs to it from being emitted.
776 Program->BSSSection->Handled = TRUE;
777 return FALSE;
778 }
779 else if (Program->ResolveAllBuiltins)
780 SetToEntryPoint = TRUE;
781 }
782 else if (SymNameMatches ("program_size"))
783 {
784 if (Program->ResolveAllBuiltins && Program->MainSection)
785 {
786 NewValue = Program->MainSection->Size;
787 HasValue = TRUE;
788 }
789 else
790 return TRUE;
791 }
792 else if (SymNameMatches ("kernel_export_table"))
793 {
794 BOOLEAN HasExports = FALSE;
795 for_each (TempSection, Program->Sections)
796 {
797 SYMBOL *TempSymbol;
798 for_each (TempSymbol, TempSection->Symbols)
799 {
800 if (TempSymbol->Exported)
801 {
802 OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
803 if (ExportNumber >= 0)
804 {
805 HasExports = TRUE;
806 TempSection->Essential = TRUE;
807 break;
808 }
809 }
810 }
811 }
812
813 if (HasExports)
814 {
815 strcpy ((char *) (Location->SymbolName), "__kernel_export_table");
816 if (TryAgain)
817 *TryAgain = TRUE;
818 return FALSE;
819 }
820 else if (Program->ResolveAllBuiltins)
821 SetToEntryPoint = TRUE;
822 }
823 #ifdef DATA_VAR_SUPPORT
824 else if (SymNameMatches ("data_var_name_end"))
825 {
826 // Point the reloc to the terminating zero byte of the name.
827 if (Program->DataVarInfo->Name)
828 {
829 strcpy ((char *) (Location->SymbolName), "__data_var_name_start");
830 Location->Offset += strlen (Program->DataVarInfo->Name) + 1;
831 if (TryAgain)
832 *TryAgain = TRUE;
833 return FALSE;
834 }
835 }
836 #endif /* DATA_VAR_SUPPORT */
837 else
838 return FALSE;
839
840 if (!SetToEntryPoint)
841 {
842 if (HasValue)
843 {
844 // Point the location to the new value.
845 Location->Symbol = NULL;
846 FreeLocationSymbolName (Section, Location);
847 Location->Offset += NewValue;
848 }
849 else if (NewSymbol)
850 {
851 // Point the location to the new symbol.
852 Location->Symbol = NewSymbol;
853 FreeLocationSymbolName (Section, Location);
854 Location->Offset += NewTargetOffset;
855 }
856 else
857 Location->Builtin = TRUE;
858
859 return TRUE;
860 }
861 }
862 // If this is a reloc to a kernel-specific symbol, point it to the
863 // entry point. The result of this is that the reloc's value
864 // becomes 0 if the reloc was made up by something like
865 // _exit-__kernel_entry_point.
866 else if (SymNameMatches ("exit") || SymNameMatches ("comment") || SymNameMatches ("extraram") || SymNameMatches ("library"))
867 SetToEntryPoint = TRUE;
868
869 if (SetToEntryPoint)
870 {
871 if (Program->EntryPoint.Symbol)
872 {
873 Location->Symbol = Program->EntryPoint.Symbol;
874 FreeLocationSymbolName (Section, Location);
875 Location->Offset += Program->EntryPoint.Offset + NewValue;
876 }
877
878 return TRUE;
879 }
880 }
881
882 return FALSE;
883 }
884
885 // Count the items for a specific built-in symbol, specified by SymName
886 // and SymNameLength. If TrueValue is nonzero, items are not counted,
887 // but NewValue is set to this value if at least one item was found. In
888 // that case, if Program->ResolveAllBuiltins is false, NewValue may be
889 // unchanged even though there are some items; you need to check back
890 // later when Program->ResolveAllBuiltins is true.
GetBuiltinValue(PROGRAM * Program,const char * SymName,SIZE SymNameLength,OFFSET * NewValue,OFFSET TrueValue)891 BOOLEAN GetBuiltinValue (PROGRAM *Program, const char *SymName, SIZE SymNameLength, OFFSET *NewValue, OFFSET TrueValue)
892 {
893 #define Count(n,op,code) \
894 ({ \
895 register OFFSET n__ = (n); \
896 if (TrueValue) \
897 { \
898 if (n__) \
899 { \
900 *NewValue = TrueValue; \
901 code; \
902 } \
903 } \
904 else \
905 *NewValue op n__; \
906 })
907 #define SetCounter(n) (Count ((n), =, (void) 0))
908 #define IncreaseCounter(n) (Count ((n), +=, break))
909
910 BOOLEAN SymNameMatches (const char *Name)
911 {
912 return (!(strncmp (SymName, Name, SymNameLength)));
913 }
914
915 SECTION *TempSection;
916 RELOC *TempReloc;
917 SYMBOL *TempSymbol;
918
919 if (SymNameMatches ("constructor"))
920 {
921 if (Program->Constructors.Start && Program->Constructors.End)
922 SetCounter ((Program->Constructors.End->Location - Program->Constructors.Start->Location) >> 2);
923 }
924 else if (SymNameMatches ("destructor"))
925 {
926 if (Program->Destructors.Start && Program->Destructors.End)
927 SetCounter ((Program->Destructors.End->Location - Program->Destructors.Start->Location) >> 2);
928 }
929 else if (SymNameMatches ("reloc"))
930 {
931 // Count all absolute relocs.
932 // Relative relocs will either be resolved completely or
933 // produce errors.
934 for_each (TempSection, Program->Sections)
935 {
936 IncreaseCounter (TempSection->Relocs.EmittedCount);
937 // Since relocs may be removed, if ResolveAllBuiltins
938 // is false, do not handle TrueValue.
939 if ((!TrueValue) || Program->ResolveAllBuiltins)
940 {
941 for_each (TempReloc, TempSection->Relocs)
942 if (!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled))))
943 IncreaseCounter (1);
944 }
945 }
946 }
947 else if (SymNameMatches ("data_ref"))
948 {
949 if (Program->DataSection)
950 {
951 // Count all absolute relocs to the data section.
952 for_each (TempSection, Program->Sections)
953 for_each (TempReloc, TempSection->Relocs)
954 if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->DataSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
955 IncreaseCounter (1);
956 }
957 }
958 else if (SymNameMatches ("bss_ref"))
959 {
960 if (Program->BSSSection)
961 {
962 // Count all absolute relocs to the BSS section.
963 for_each (TempSection, Program->Sections)
964 for_each (TempReloc, TempSection->Relocs)
965 if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->BSSSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
966 IncreaseCounter (1);
967 }
968 }
969 else if (SymNameMatches ("rom_call"))
970 {
971 for_each (TempSection, Program->Sections)
972 IncreaseCounter (CountItems (TempSection->ROMCalls, ROM_CALL));
973 }
974 else if (SymNameMatches ("ram_call"))
975 {
976 for_each (TempSection, Program->Sections)
977 IncreaseCounter (CountItems (TempSection->RAMCalls, RAM_CALL));
978 }
979 else if (SymNameMatches ("lib"))
980 SetCounter (CountItems (Program->Libraries, LIBRARY));
981 else if (SymNameMatches ("referenced_lib"))
982 SetCounter (Program->Libraries.ReferencedCount);
983 else if (SymNameMatches ("export"))
984 {
985 // The number of exports is equal to the highest export number + 1.
986 for_each (TempSection, Program->Sections)
987 {
988 for_each (TempSymbol, TempSection->Symbols)
989 {
990 if (TempSymbol->Exported)
991 {
992 OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
993 if ((ExportNumber >= 0) && (*NewValue < ExportNumber + 1))
994 Count (ExportNumber + 1, =, break);
995 }
996 }
997 }
998 }
999 else if (SymNameMatches ("nostub_comment"))
1000 {
1001 for_each (TempSection, Program->Sections)
1002 {
1003 for_each (TempSymbol, TempSection->Symbols)
1004 {
1005 if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, SYMPF_NOSTUB_DATA, sizeof (SYMPF_NOSTUB_DATA) - 1))))
1006 {
1007 OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + (sizeof (SYMPF_NOSTUB_DATA_START) - 1));
1008 if (ExportNumber >= 0)
1009 IncreaseCounter (1);
1010 }
1011 }
1012 }
1013 }
1014 else
1015 return FALSE;
1016
1017 #undef IncreaseCounter
1018 #undef SetCounter
1019 #undef Count
1020
1021 return TRUE;
1022 }
1023
1024 // If the given symbol name belongs to a calculator-specific builtin
1025 // symbol, return a pointer to the part of it that holds the values.
GetCalcBuiltinValues(const char * SymName)1026 static const char *GetCalcBuiltinValues (const char *SymName)
1027 {
1028 if (!(strncmp (SymName, SYMPF_BUILTIN_CALC_CONST, sizeof (SYMPF_BUILTIN_CALC_CONST) - 1)))
1029 {
1030 return (SymName + (sizeof (SYMPF_BUILTIN_CALC_CONST) - 1));
1031 }
1032 return NULL;
1033 }
1034
1035 // Check if the given location points to a calculator-specific builtin
1036 // symbol.
IsCalcBuiltinLocation(const LOCATION * Location)1037 BOOLEAN IsCalcBuiltinLocation (const LOCATION *Location)
1038 {
1039 return (Location->SymbolName && (GetCalcBuiltinValues (Location->SymbolName) || (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))));
1040 }
1041
1042 // Return whether the reloc can be resolved to a calculator-specific value.
1043 // ResolveSpecialSymbol or something related must have been called on the
1044 // reloc at least once.
IsPlainCalcBuiltin(const RELOC * Reloc)1045 BOOLEAN IsPlainCalcBuiltin (const RELOC *Reloc)
1046 {
1047 // To improve speed, check whether the target and relation (if it exists)
1048 // are builtin symbols.
1049 if (Reloc->Target.Builtin && ((!(Reloc->Relation)) || Reloc->Relation->Builtin))
1050 {
1051 // Check the target.
1052 if (IsCalcBuiltinLocation (&(Reloc->Target)))
1053 {
1054 // If there is a relation, check it.
1055 if (Reloc->Relation)
1056 return IsCalcBuiltinLocation (Reloc->Relation);
1057 // Otherwise, the reloc may not be relative, since that would
1058 // mean that it cannot be resolved to a number.
1059 else
1060 return (!(Reloc->Relative));
1061 }
1062 }
1063
1064 return FALSE;
1065 }
1066
1067 // If the location can be resolved to a calculator-specific value, get the
1068 // value for the specified calculator.
1069 // If IsCalcBuiltinLocation returned a positive result for this reloc, this
1070 // function will not return a negative result.
GetCalcBuiltinLocationValue(const LOCATION * Location,ProgramCalcs DestCalc,IMAX * Value)1071 BOOLEAN GetCalcBuiltinLocationValue (const LOCATION *Location, ProgramCalcs DestCalc, IMAX *Value)
1072 {
1073 // Basic sanity checks.
1074 if (Value && Location->SymbolName)
1075 {
1076 // Special case: __ld_hardware_id
1077 if (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))
1078 {
1079 switch (DestCalc)
1080 {
1081 case CALC_TI89:
1082 *Value = 3;
1083 break;
1084
1085 case CALC_TI89 | CALC_FLAG_TITANIUM:
1086 *Value = 9;
1087 break;
1088
1089 case CALC_TI92PLUS:
1090 *Value = 1;
1091 break;
1092
1093 case CALC_V200:
1094 *Value = 8;
1095 break;
1096
1097 default:
1098 Warning (NULL, SYM_BUILTIN_HARDWARE_ID " not defined for this calculator.");
1099 *Value = 0;
1100 }
1101 *Value += Location->Offset;
1102 return TRUE;
1103 }
1104 else
1105 {
1106 // Get the part of the symbol name that holds the values,
1107 // separated by '_'.
1108 const char *Values = GetCalcBuiltinValues (Location->SymbolName);
1109 if (Values)
1110 {
1111 // AND out the calculator flags.
1112 DestCalc &= ~CALC_FLAG_TITANIUM;
1113
1114 // While we still have at least one value left...
1115 while (Values)
1116 {
1117 // Get the end of the value string.
1118 const char *ValueEnd = strchr (Values, '_');
1119 SIZE ValueSize = ValueEnd ? (SIZE) (ValueEnd - Values) : (SIZE) (strlen (Values));
1120
1121 // If this is the value that belongs to the current calculator,
1122 // extract the value and return.
1123 if (DestCalc == 1)
1124 {
1125 char *EndPtr = NULL;
1126
1127 // Create a copy of the value, with a terminating zero byte.
1128 char ValueStr[ValueSize+1];
1129 strncpy (ValueStr, Values, ValueSize);
1130 ValueStr [ValueSize] = 0;
1131
1132 // Convert this string into a number and return it.
1133 *Value = strtoul (ValueStr, &EndPtr, 0);
1134 if (EndPtr && *EndPtr)
1135 Warning (NULL, "Invalid number `%s' in `%s'.", ValueStr, Location->SymbolName);
1136 *Value += Location->Offset;
1137
1138 return TRUE;
1139 }
1140
1141 // Advance to the next value.
1142 Values = ValueEnd ? ValueEnd + 1 : NULL;
1143 // Advance to the next calculator.
1144 DestCalc >>= 1;
1145 }
1146
1147 // No more values were found, but the function did not exit yet.
1148 Warning (NULL, "Calculator constant `%s' contains too few values.", Location->SymbolName);
1149 *Value = 0;
1150
1151 // We have to return a positive result anyway because
1152 // IsCalcBuiltinLocation would as well.
1153 return TRUE;
1154 }
1155 }
1156 }
1157
1158 return FALSE;
1159 }
1160
1161 // If the reloc can be resolved to a calculator-specific value, get the
1162 // value for the specified calculator.
1163 // The return value is the same as for IsPlainCalcBuiltin.
GetCalcBuiltinValue(const RELOC * Reloc,ProgramCalcs DestCalc,IMAX * Value)1164 BOOLEAN GetCalcBuiltinValue (const RELOC *Reloc, ProgramCalcs DestCalc, IMAX *Value)
1165 {
1166 if (Value)
1167 {
1168 // Get the value for the target.
1169 if (GetCalcBuiltinLocationValue (&(Reloc->Target), DestCalc, Value))
1170 {
1171 // If there is a relation, subtract its value.
1172 if (Reloc->Relation)
1173 {
1174 IMAX RelationValue;
1175 if (!(GetCalcBuiltinLocationValue (Reloc->Relation, DestCalc, &RelationValue)))
1176 return FALSE;
1177 *Value -= RelationValue;
1178 }
1179 // Otherwise, the reloc may not be relative
1180 // (see IsPlainCalcBuiltin).
1181 else if (Reloc->Relative)
1182 return FALSE;
1183
1184 *Value += Reloc->FixedOffset;
1185 return TRUE;
1186 }
1187 }
1188
1189 return FALSE;
1190 }
1191
1192 // If required by some special symbol(s) at the end of the section,
1193 // modify the contents of the section.
1194 // This can be used to insert special items such as relocation entries.
1195 // MergedSection specifies the (usually large) part of the program that
1196 // has already been merged.
1197 // If necessary, MergedSection is frozen automatically.
HandleSectionContents(SECTION * Section,SECTION * MergedSection)1198 BOOLEAN HandleSectionContents (SECTION *Section, SECTION *MergedSection)
1199 {
1200 SYMBOL *Symbol;
1201
1202 // Search the labels at the end of the secion to find special ones.
1203 for (Symbol = FindSymbolAtPos (Section, Section->Size, TRUE); Symbol; Symbol = GetNext (Symbol))
1204 {
1205 if (!(strncmp (Symbol->Name, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
1206 return (HandleInsertion (Section, Symbol->Location, Symbol->Name + sizeof (SYMPF_BUILTIN_INSERT) - 1, MergedSection, FALSE));
1207 }
1208
1209 return TRUE;
1210 }
1211
1212 // Insert contents for an insertion specified by SymbolName, and return
1213 // a symbol from where the insertion took place.
1214 // If necessary, Section is frozen automatically.
HandleAutoInsertion(SECTION * Section,const char * SymbolName)1215 SYMBOL *HandleAutoInsertion (SECTION *Section, const char *SymbolName)
1216 {
1217 if (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
1218 {
1219 CreateSectionSegment (Section);
1220
1221 // All insertions except compressed ones should be aligned on a 2-byte boundary.
1222 if ((!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_COMPRESSED, sizeof (SYMPF_BUILTIN_INSERT_COMPRESSED) - 1)))
1223 || (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_MLINK, sizeof (SYMPF_BUILTIN_INSERT_MLINK) - 1)))
1224 || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "fargo021_relocs")))
1225 || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "preos_compressed_tables")))
1226 || PadSection (Section, 2))
1227 {
1228 // Create a new symbol at the end of the section.
1229 SYMBOL *Result = calloc (1, sizeof (SYMBOL));
1230
1231 if (Result)
1232 {
1233 Result->Parent = Section;
1234 Result->Location = Section->Size;
1235 strncpy (Result->Name, SymbolName, MAX_SYM_LEN);
1236 Result->Exported = TRUE;
1237 Append (Section->Symbols, Result);
1238
1239 // Insert the data.
1240 if (AppendInsertionData (Section, SymbolName + sizeof (SYMPF_BUILTIN_INSERT) - 1, Section, TRUE))
1241 return Result;
1242 }
1243 else
1244 Error (NULL, "Out of memory.");
1245 }
1246 }
1247
1248 return NULL;
1249 }
1250
1251 // Handle an insertion by cutting the section off at the specified location
1252 // and inserting the contents specified by the name, taking into account
1253 // that MergedSection specifies the (usually large) part of the program
1254 // that has already been merged.
HandleInsertion(SECTION * Section,OFFSET Location,const char * Name,SECTION * MergedSection,BOOLEAN AlwaysTerminate)1255 BOOLEAN HandleInsertion (SECTION *Section, OFFSET Location, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
1256 {
1257 if (Location == Section->Size)
1258 return AppendInsertionData (Section, Name, MergedSection, AlwaysTerminate);
1259 else
1260 return TRUE;
1261 }
1262
1263 // Append the data required by an insertion (specified by name) to the
1264 // section specified by Section, taking into account that MergedSection
1265 // specifies the (usually large) part of the program that has already
1266 // been merged.
AppendInsertionData(SECTION * Section,const char * Name,SECTION * MergedSection,BOOLEAN AlwaysTerminate)1267 BOOLEAN AppendInsertionData (SECTION *Section, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
1268 {
1269 BOOLEAN NameMatches (const char *InsertionName)
1270 {
1271 return (!(strcmp (Name, InsertionName)));
1272 }
1273
1274 PROGRAM *Program = Section->Parent;
1275
1276 #ifdef DATA_VAR_SUPPORT
1277 // Data variable name.
1278 if (NameMatches ("data_var_name"))
1279 return InsertDataVarName (Section);
1280 else
1281 #endif /* DATA_VAR_SUPPORT */
1282
1283 // Nostub-specific formats.
1284 if (NameMatches ("nostub_comments"))
1285 return InsertNostubComments (Section);
1286
1287 // Kernel-specific formats.
1288 else if (NameMatches ("kernel_relocs"))
1289 return InsertKernelRelocs (Section, NULL);
1290 else if (NameMatches ("kernel_bss_refs"))
1291 return InsertKernelSectionRefs (Section, Program->BSSSection, AlwaysTerminate);
1292 else if (NameMatches ("kernel_data_refs"))
1293 return InsertKernelSectionRefs (Section, Program->DataSection, AlwaysTerminate);
1294 else if (NameMatches ("kernel_rom_calls"))
1295 return InsertKernelROMCalls (Section);
1296 else if (NameMatches ("kernel_ram_calls"))
1297 return InsertKernelRAMCalls (Section);
1298 else if (NameMatches ("kernel_libs"))
1299 return InsertKernelLibraries (Section);
1300 else if (NameMatches ("kernel_exports"))
1301 return InsertKernelExports (Section, TRUE);
1302
1303 #ifdef FARGO_SUPPORT
1304 // Fargo-specific formats.
1305 else if (NameMatches ("fargo_exports"))
1306 return InsertKernelExports (Section, FALSE);
1307 else if (NameMatches ("fargo020_bss_refs"))
1308 return InsertKernelSectionRefs (Section, Program->BSSSection, TRUE);
1309 else if (NameMatches ("fargo020_libs"))
1310 return InsertFargo020Libraries (Section);
1311 #endif /* FARGO_SUPPORT */
1312
1313 // PreOS-specific formats.
1314 else if (NameMatches ("preos_compressed_tables"))
1315 return InsertPreOsCompressedTables (Section);
1316
1317 // Other compressed formats.
1318 else
1319 {
1320 char *ReferenceName = malloc ((sizeof (SYMPF_BUILTIN) - 1) + strlen (Name) + sizeof ("_ref"));
1321
1322 if (ReferenceName)
1323 {
1324 // Build the reference symbol name: "__ld_" Name "_ref".
1325 strcpy (ReferenceName, SYMPF_BUILTIN);
1326 strcat (ReferenceName, Name);
1327 strcat (ReferenceName, "_ref");
1328
1329 {
1330 LOCATION Reference = {NULL, ReferenceName, 0, FALSE};
1331
1332 // Try to find a reference symbol. If none is found, use
1333 // the program entry point.
1334 Section->Relocs.UnresolvedCount++;
1335 if (!(ResolveLocation (Program, Section, &Reference)))
1336 {
1337 FreeLocationSymbolName (Section, &Reference);
1338 Reference = Program->EntryPoint;
1339 }
1340
1341 #ifdef FARGO_SUPPORT
1342 // Fargo-specific formats.
1343 if (NameMatches ("fargo021_relocs"))
1344 return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
1345 else if (NameMatches ("fargo021_bss_refs"))
1346 return InsertFargo021SectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
1347 else if (NameMatches ("fargo021_libs"))
1348 return InsertFargo021Libraries (Section, MergedSection, &Reference);
1349 #endif /* FARGO_SUPPORT */
1350
1351 // Compressed relocation tables using our own format.
1352 else if (NameMatches ("compressed_relocs"))
1353 return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
1354 else if (NameMatches ("compressed_bss_refs"))
1355 return InsertCompressedSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
1356 else if (NameMatches ("compressed_data_refs"))
1357 return InsertCompressedSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
1358 else if (NameMatches ("compressed_rom_calls"))
1359 return InsertCompressedROMCalls (Section, MergedSection, &Reference);
1360
1361 // Compressed relocation tables using our own mlink-style format.
1362 else if (NameMatches ("mlink_relocs"))
1363 return InsertMlinkRelocs (Section, NULL, MergedSection, &Reference);
1364 else if (NameMatches ("mlink_bss_refs"))
1365 return InsertMlinkSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
1366 else if (NameMatches ("mlink_data_refs"))
1367 return InsertMlinkSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
1368 else if (NameMatches ("mlink_rom_calls"))
1369 return InsertMlinkROMCalls (Section, MergedSection, &Reference);
1370
1371 else
1372 Warning (GetFileName (Section, Section->Size), "Unrecognized insertion `%s'.", Name);
1373 }
1374 }
1375 else
1376 {
1377 Error (NULL, "Out of memory.");
1378 return FALSE;
1379 }
1380 }
1381
1382 return TRUE;
1383 }
1384