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