1 /* imp_amig.c: Routines to import an AmigaOS-hunks file
2
3 Copyright (C) 2002-2005 Kevin Kofler
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18
19 #include "imp_amig.h"
20
21 #ifdef AMIGAOS_SUPPORT
22
23 #include "../formats/amigaos.h"
24 #include "../manip.h"
25 #include "../special.h"
26 #include "../bincode/fix_m68k.h"
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 // reallocate array, free it if reallocation failed, zero out the added size
32 // otherwise
crealloc(void * array,SIZE oldSize,SIZE newSize)33 static void *crealloc(void *array, SIZE oldSize, SIZE newSize)
34 {
35 void *p = realloc(array, newSize);
36 if (!p) {
37 if (array) {
38 free(array);
39 }
40 return NULL;
41 }
42 if (newSize > oldSize) {
43 memset(((I1*)p)+oldSize, 0, newSize-oldSize);
44 }
45 return p;
46 }
47
48 // Defines by how much the reloc target hunks array is grown.
49 #define RELOC_TARGET_HUNKS_INCREMENT (5 * sizeof(SECTION*))
50
51 // Import an AmigaOS-hunks file into the internal data structures.
ImportAmigaOSFile(PROGRAM * Program,const I1 * File,SIZE FileSize,const char * FileName)52 BOOLEAN ImportAmigaOSFile (PROGRAM *Program, const I1 *File, SIZE FileSize, const char *FileName)
53 {
54 // Call this for a nice and clean failing exit.
55 #define Fail() ({if(currSectionData) free(currSectionData);if(hunkName) free(hunkName);if(symName) free(symName);if(relocTargetHunks) free(relocTargetHunks);return FALSE;})
56 #define FailWithError(ErrorMsg...) ({Error (FileName, ErrorMsg); Fail ();})
57 #define TestMem(Ptr) ({ if (!(Ptr)) {FailWithError ("Out of memory.");} })
58
59 // Check if a given object with a given type is completely inside the file.
60 #define IsInFile(Ptr,Type) ((Ptr) >= File && (Ptr) + sizeof (Type) <= File + FileSize)
61 #define TestInFile(Ptr,Type) ({ if (!(IsInFile (Ptr, Type))) {FailWithError ("Corrupt A68k object file.");} })
62
63 // Get next big-endian longint. We will need this in many places here, since
64 // unlike COFF, AmigaOS-hunks is a sequential format, not a pointer-based one.
65 #define GetNextTI4(Ptr) ({register TI4 __TI4;TestInFile(Ptr,TI4);__TI4=(*((TI4*)Ptr));Ptr+=4;ReadTI4(__TI4);})
66
67 // Local Variables
68 const I1 *ptr = File;
69 I4 hunkSize;
70 char *hunkName = NULL, *symName = NULL;
71 SECTION *currSection = NULL;
72 SYMBOL *currSymbol;
73 I1 *currSectionData = NULL;
74 OFFSET StartupNumber;
75 BOOLEAN InitializeBSS = TRUE;
76 BOOLEAN AllRelocs = FALSE;
77 COUNT numRelocTargetHunks=0; // number of hunks which are candidates for reloc targets
78 SECTION **relocTargetHunks=NULL;
79 SIZE relocTargetHunksSize=0;
80 const RELOC *relocHint=NULL;
81
82 // Read unit hunk
83 if (GetNextTI4(ptr) != AMIGAOS_HUNK_UNIT)
84 // This should already be trapped by IsAmigaOSFile, but just to make sure.
85 FailWithError("Corrupt A68k object file (unit hunk missing).");
86 hunkSize = GetNextTI4(ptr)<<2;
87 TestInFile(ptr,I1[hunkSize]);
88 ptr += hunkSize;
89
90 while (ptr < (File + FileSize)) {
91 I4 hunkType = GetNextTI4(ptr);
92
93 // Hunk flags:
94 // AMIGAOS_HUNK_FLAG_ADVISORY:
95 // A68k never generates this one
96 if (hunkType & AMIGAOS_HUNK_FLAG_ADVISORY)
97 FailWithError("Unsupported hunk flag `advisory'.");
98 // AMIGAOS_HUNK_FLAG_CHIP,
99 // AMIGAOS_HUNK_FLAG_FAST:
100 // simply ignore those flags, they have no meaning on TI calculators
101 hunkType &= AMIGAOS_HUNK_TYPE_MASK;
102
103 switch (hunkType) {
104 // beginning section - there should be only one of those, handled above
105 case AMIGAOS_HUNK_UNIT:
106 FailWithError("Corrupt A68k object file (duplicate unit hunk).");
107 break;
108
109 // name of the section to follow - temporarily store a pointer to it
110 case AMIGAOS_HUNK_NAME:
111 hunkSize = GetNextTI4(ptr)<<2;
112 TestInFile(ptr,I1[hunkSize]);
113 hunkName = malloc(hunkSize+1);
114 TestMem(hunkName);
115 strncpy(hunkName,ptr,hunkSize);
116 hunkName[hunkSize]=0;
117 ptr += hunkSize;
118 break;
119
120 case AMIGAOS_HUNK_CODE:
121 case AMIGAOS_HUNK_DATA:
122 // allocate space for at least one more reloc target hunk
123 while ((SIZE) ((numRelocTargetHunks+1) * sizeof(SECTION*)) > relocTargetHunksSize) {
124 relocTargetHunks = crealloc(relocTargetHunks, relocTargetHunksSize,
125 relocTargetHunksSize+RELOC_TARGET_HUNKS_INCREMENT);
126 TestMem(relocTargetHunks);
127 relocTargetHunksSize += RELOC_TARGET_HUNKS_INCREMENT;
128 }
129
130 // invent a section name if no reasonable one given
131 if (!hunkName || !*hunkName || *hunkName==' ') {
132 if (hunkName) {
133 free(hunkName);
134 }
135 hunkName = malloc(sizeof(".data"));
136 TestMem(hunkName);
137 strcpy(hunkName,((hunkType == AMIGAOS_HUNK_CODE)?".text":".data"));
138 }
139
140 // determine whether it is a startup section
141 // This is very important as we cannot omit it.
142 StartupNumber = GetStartupSectionNumber (hunkName, strlen(hunkName));
143
144 hunkSize = GetNextTI4(ptr)<<2;
145 // omit empty sections to simplify the output
146 if ((!StartupNumber) && (!hunkSize)) {
147 free(hunkName);
148 hunkName=NULL;
149 break; // no data to skip - there is none!
150 }
151
152 // Section is not empty (or a startup section).
153 // Try to allocate data for the section, if necessary.
154 TestInFile(ptr,I1[hunkSize]);
155 TestMem ((currSectionData = calloc (hunkSize, 1)));
156 memcpy (currSectionData, ptr, hunkSize);
157 ptr += hunkSize;
158
159 // create a new section, initialize it, and append it to the list of sections.
160 if (relocTargetHunks[numRelocTargetHunks]) {
161 currSection = relocTargetHunks[numRelocTargetHunks];
162 } else {
163 currSection = calloc (1, sizeof (SECTION));
164 TestMem (currSection);
165 currSection->Parent = Program;
166 currSection->FileName = FileName;
167 }
168
169 currSection->Data = currSectionData;
170 currSection->Size = hunkSize;
171 currSection->Code = (hunkType == AMIGAOS_HUNK_CODE);
172 currSection->Initialized = TRUE;
173 currSection->StartupNumber = StartupNumber;
174 currSection->Constructors = (!(strcmp (hunkName, ".ctors")));
175 currSection->Destructors = (!(strcmp (hunkName, ".dtors")));
176 currSection->CanCutRanges = AllRelocs;
177
178 InsertSection (Program, currSection);
179
180 if (!(CreateSectionSymbol (currSection, hunkName)))
181 Fail ();
182
183 relocTargetHunks[numRelocTargetHunks++] = currSection;
184 currSectionData = NULL; // don't free handles already in linked list!
185
186 if (hunkType == AMIGAOS_HUNK_CODE && Program->OptimizeInfo->OptimizeNOPs)
187 M68kRemoveTrailingNOP (currSection);
188
189 free(hunkName);
190 hunkName = NULL;
191 break;
192
193 case AMIGAOS_HUNK_BSS:
194 // allocate space for at least one more reloc target hunk
195 while ((SIZE) ((numRelocTargetHunks+1) * sizeof(SECTION*)) > relocTargetHunksSize) {
196 relocTargetHunks = crealloc(relocTargetHunks, relocTargetHunksSize,
197 relocTargetHunksSize+RELOC_TARGET_HUNKS_INCREMENT);
198 TestMem(relocTargetHunks);
199 relocTargetHunksSize += RELOC_TARGET_HUNKS_INCREMENT;
200 }
201
202 // invent a section name if no reasonable one given
203 if (!hunkName || !*hunkName || *hunkName==' ') {
204 if (hunkName) {
205 free(hunkName);
206 }
207 hunkName = malloc(sizeof(".bss"));
208 TestMem(hunkName);
209 strcpy(hunkName,".bss");
210 }
211
212 hunkSize = GetNextTI4(ptr)<<2;
213 // omit empty sections to simplify the output
214 if (!hunkSize) break; // no data to skip - there is none!
215
216 // Section is not empty.
217 // create a new section, initialize it, and append it to the list of sections.
218 if (relocTargetHunks[numRelocTargetHunks]) {
219 currSection = relocTargetHunks[numRelocTargetHunks];
220 } else {
221 currSection = calloc (1, sizeof (SECTION));
222 TestMem (currSection);
223 currSection->Parent = Program;
224 currSection->FileName = FileName;
225 }
226
227 currSection->Initialized = InitializeBSS;
228 currSection->Size = hunkSize;
229 currSection->CanCutRanges = AllRelocs;
230
231 Append (Program->Sections, currSection);
232
233 if (!(CreateSectionSymbol (currSection, hunkName)))
234 Fail ();
235
236 relocTargetHunks[numRelocTargetHunks++] = currSection;
237
238 free(hunkName);
239 hunkName = NULL;
240 break;
241
242 case AMIGAOS_HUNK_RELOC_REL1:
243 case AMIGAOS_HUNK_RELOC_REL2:
244 case AMIGAOS_HUNK_RELOC_REL4:
245 case AMIGAOS_HUNK_RELOC_ABS2:
246 case AMIGAOS_HUNK_RELOC_ABS4:
247 // make sure we have a section to put those relocs into
248 if (!currSection)
249 FailWithError("Relocation hunk (type `0x%lX') without context.",(long)hunkType);
250
251 {
252 SIZE relocSize = 0;
253 BOOLEAN relative = FALSE;
254 switch (hunkType) {
255 case AMIGAOS_HUNK_RELOC_REL1:
256 relative = TRUE;
257 relocSize = 1;
258 break;
259 case AMIGAOS_HUNK_RELOC_REL2:
260 relative = TRUE;
261 case AMIGAOS_HUNK_RELOC_ABS2:
262 relocSize = 2;
263 break;
264 case AMIGAOS_HUNK_RELOC_REL4:
265 relative = TRUE;
266 case AMIGAOS_HUNK_RELOC_ABS4:
267 relocSize = 4;
268 break;
269 }
270
271 hunkSize = GetNextTI4(ptr); // hunkSize is the number of relocs here.
272
273 while (hunkSize) {
274 OFFSET targetHunkNumber = GetNextTI4(ptr);
275 SECTION *targetHunk;
276 OFFSET i;
277
278 // allocate space for at least one more reloc target hunk
279 while ((SIZE) ((targetHunkNumber+1) * sizeof(SECTION*)) > relocTargetHunksSize) {
280 relocTargetHunks = crealloc(relocTargetHunks, relocTargetHunksSize,
281 relocTargetHunksSize+RELOC_TARGET_HUNKS_INCREMENT);
282 TestMem(relocTargetHunks);
283 relocTargetHunksSize += RELOC_TARGET_HUNKS_INCREMENT;
284 }
285
286 targetHunk = relocTargetHunks[targetHunkNumber];
287 if (!targetHunk) {
288 // create placeholder for section right now
289 targetHunk = calloc (1, sizeof (SECTION));
290 TestMem(targetHunk);
291 // initialize the fields to something acceptable to the backend:
292 // the dummy section is a 0-byte BSS section
293 targetHunk->Parent = Program;
294 targetHunk->FileName = FileName;
295
296 // This will get overwritten when the real section will be read in.
297 // Otherwise, the "targetHunk" section reference was invalid, hence
298 // the name of the dummy symbol.
299 if (!(CreateSectionSymbol (targetHunk, "(invalid AmigaOS target section)")))
300 Fail ();
301
302 relocTargetHunks[targetHunkNumber] = targetHunk;
303 }
304
305 for (i=0; i<(SIZE)hunkSize; i++) {
306 RELOC *newReloc;
307 I4 location = GetNextTI4(ptr);
308 OFFSET targetOffset = 0;
309 BOOLEAN unoptimizable = FALSE;
310 #ifdef AMIGAOS_TIGCC_EXTENSIONS
311 unoptimizable = !!(location&AMIGAOS_RELOC_UNOPTIMIZABLE);
312 location &= ~AMIGAOS_RELOC_UNOPTIMIZABLE;
313 #endif
314 newReloc = calloc (1, sizeof (RELOC));
315 TestMem (newReloc);
316 newReloc->Parent = currSection;
317 newReloc->Location = location;
318 newReloc->Target.Symbol = targetHunk->SectionSymbol;
319 newReloc->Target.SymbolName = newReloc->Target.Symbol->Name;
320 newReloc->Size = relocSize;
321 newReloc->Relative = relative;
322 newReloc->Unoptimizable = unoptimizable;
323 if ((OFFSET) (location+relocSize) <= currSection->Size) {
324 if (currSection->Data) {
325 targetOffset = ReadSTI(currSection->Data+location,relocSize);
326 // Zero out the section contents.
327 memset(currSection->Data+location,0,relocSize);
328 // We have to guess the first bytes of the targetOffset. This is
329 // the easiest way to do it.
330 if (targetHunk != currSection) {
331 OFFSET maxDistance = 1 << ((relocSize * 8) - 1);
332 // If the section is in front of the current section,
333 // set the reference location as close to the end as possible.
334 if (targetHunkNumber < (numRelocTargetHunks - 1)) {
335 location = targetHunk->Size - (maxDistance - 1);
336 // Otherwise, set the reference location as close to the start as possible.
337 } else {
338 location = maxDistance;
339 }
340 }
341 {
342 SI4 difference = targetOffset - location;
343 if (relocSize <= 1) {
344 targetOffset = location + ((SI1) difference);
345 } else if (relocSize <= 2) {
346 targetOffset = location + ((SI2) difference);
347 }
348 }
349 } else {
350 Warning(FileName,"Adding reloc at 0x%lX in section `%s' without data to section `%s'.",(long)location,currSection->SectionSymbol->Name,newReloc->Target.SymbolName);
351 }
352 } else {
353 Warning(FileName,"Invalid reloc location `0x%lX' in size 4 reloc table for origin section `%s' and target section `%s'",(long)location,currSection->SectionSymbol->Name,newReloc->Target.SymbolName);
354 }
355
356 // Apply architecture-specific fixes to the offset.
357 newReloc->Target.Offset = ((currSection->Code && newReloc->Target.Symbol->Parent->Code) ? M68kFixTargetOffset (targetOffset, newReloc->Size, newReloc->Relative) : targetOffset);
358
359 // Calculate the remaining part of the offset.
360 newReloc->FixedOffset = targetOffset - newReloc->Target.Offset;
361
362 // Put this reloc into the linked list.
363 InsertReloc(currSection,newReloc);
364 }
365
366 hunkSize = GetNextTI4(ptr);
367 }
368 }
369 break;
370
371 #ifdef AMIGAOS_TIGCC_EXTENSIONS
372 case AMIGAOS_HUNK_RELOC_ABS1_POSNEG:
373 case AMIGAOS_HUNK_RELOC_ABS2_POSNEG:
374 case AMIGAOS_HUNK_RELOC_ABS4_POSNEG:
375 // make sure we have a section to put those relocs into
376 if (!currSection)
377 FailWithError("Relocation hunk (type `0x%lX') without context.",(long)hunkType);
378
379 {
380 OFFSET i;
381 SIZE relocSize = 0;
382
383 switch (hunkType) {
384 case AMIGAOS_HUNK_RELOC_ABS1_POSNEG:
385 relocSize = 1;
386 break;
387 case AMIGAOS_HUNK_RELOC_ABS2_POSNEG:
388 relocSize = 2;
389 break;
390 case AMIGAOS_HUNK_RELOC_ABS4_POSNEG:
391 relocSize = 4;
392 break;
393 }
394
395 hunkSize = GetNextTI4(ptr); // hunkSize is the number of relocs here.
396
397 for (i=0; i<(SIZE)hunkSize; i++) {
398 RELOC *newReloc;
399 OFFSET targetHunkNumber = GetNextTI4(ptr);
400 SECTION *targetHunk;
401 I4 location;
402 OFFSET targetOffset;
403 BOOLEAN unoptimizable;
404
405 // allocate space for at least one more reloc target hunk
406 while ((SIZE) ((targetHunkNumber+1) * sizeof(SECTION*)) > relocTargetHunksSize) {
407 relocTargetHunks = crealloc(relocTargetHunks, relocTargetHunksSize,
408 relocTargetHunksSize+RELOC_TARGET_HUNKS_INCREMENT);
409 TestMem(relocTargetHunks);
410 relocTargetHunksSize += RELOC_TARGET_HUNKS_INCREMENT;
411 }
412
413 targetHunk = relocTargetHunks[targetHunkNumber];
414 if (!targetHunk) {
415 // create placeholder for section right now
416 targetHunk = calloc (1, sizeof (SECTION));
417 TestMem(targetHunk);
418 // initialize the fields to something acceptable to the backend:
419 // the dummy section is a 0-byte BSS section
420 targetHunk->Parent = Program;
421 targetHunk->FileName = FileName;
422
423 // This will get overwritten when the real section will be read in.
424 // Otherwise, the "targetHunk" section reference was invalid, hence
425 // the name of the dummy symbol.
426 if (!(CreateSectionSymbol (targetHunk, "(invalid AmigaOS target section)")))
427 Fail ();
428
429 relocTargetHunks[targetHunkNumber] = targetHunk;
430 }
431
432 location = GetNextTI4(ptr);
433 unoptimizable = !!(location&AMIGAOS_RELOC_UNOPTIMIZABLE);
434 location &= ~AMIGAOS_RELOC_UNOPTIMIZABLE;
435 targetOffset = GetNextTI4(ptr);
436 if (GetNextTI4(ptr)) { // negative reloc
437 RELOC *PositiveReloc = NULL;
438
439 // Find a matching positive reloc.
440 PositiveReloc = FindMatchingReloc (currSection, location, relocSize, FALSE, NULL, relocHint);
441
442 if (PositiveReloc) {
443 LOCATION *relation = calloc (1, sizeof (LOCATION));
444 TestMem (relation);
445 relation->Symbol = targetHunk->SectionSymbol;
446 relation->SymbolName = relation->Symbol->Name;
447 relation->Offset = targetOffset;
448 PositiveReloc->Relative = TRUE;
449 PositiveReloc->Relation = relation;
450 HandleLocation(PositiveReloc, relation);
451
452 relocHint = PositiveReloc;
453 } else {
454 Warning (FileName, "Removing negative reloc at 0x%lX with no matching positive reloc.", (long) location);
455 }
456 } else { // positive reloc
457 newReloc = calloc (1, sizeof (RELOC));
458 TestMem (newReloc);
459 newReloc->Parent = currSection;
460 newReloc->Location = location;
461 newReloc->Target.Symbol = targetHunk->SectionSymbol;
462 newReloc->Target.SymbolName = newReloc->Target.Symbol->Name;
463 newReloc->Target.Offset = targetOffset;
464 newReloc->Size = relocSize;
465 newReloc->Relative = FALSE;
466 newReloc->Unoptimizable = unoptimizable;
467
468 // Those hunks put the target offset in the relocation table. However, we have to
469 // read a possible FixedOffset from the data stream.
470 if ((OFFSET) (location+relocSize) <= currSection->Size) {
471 if (currSection->Data) {
472 newReloc->FixedOffset = ReadSTI(currSection->Data+location,relocSize);
473 // Zero out the section contents.
474 memset(currSection->Data+location,0,relocSize);
475 } else {
476 Warning(FileName,"Adding reloc at 0x%lX in section `%s' without data to section `%s'.",(long)location,currSection->SectionSymbol->Name,newReloc->Target.SymbolName);
477 }
478 } else {
479 Warning(FileName,"Invalid reloc location `0x%lX' in extended size %ld reloc table for origin section `%s' and target section `%s'",(long)location,(long)relocSize,currSection->SectionSymbol->Name,newReloc->Target.SymbolName);
480 }
481
482 // Put this reloc into the linked list.
483 InsertReloc(currSection,newReloc);
484 }
485 }
486 }
487 break;
488 #endif
489
490 case AMIGAOS_HUNK_END:
491 // Do nothing - we already skipped the hunk type, and that's all we need
492 // to do here.
493 break;
494
495 case AMIGAOS_HUNK_EXT:
496 // make sure we have a section to put those symbols into
497 if (!currSection)
498 FailWithError("Symbol import/export hunk without context.");
499 hunkSize = GetNextTI4(ptr);
500 while (hunkSize) {
501 // The most significant byte of the size longword encodes the symbol type.
502 hunkType = hunkSize >> 24;
503 hunkSize = (hunkSize&0xffffffL)<<2;
504
505 TestInFile(ptr,I1[hunkSize]);
506 symName = malloc(hunkSize+1);
507 TestMem(symName);
508 strncpy(symName,ptr,hunkSize);
509 symName[hunkSize]=0;
510 ptr+=hunkSize;
511
512 switch (hunkType) {
513 // Definitions:
514 // Absolute definition: we cannot use those, but ignoring them
515 // should not be fatal, so we will ignore them with a warning.
516 case AMIGAOS_EXT_ABS:
517 Warning(FileName,"Cannot handle absolute symbol `%s'.",symName);
518 TestInFile(ptr,TI4);
519 ptr+=4;
520 break;
521
522 // Standard definition (offset from a section):
523 case AMIGAOS_EXT_DEF: {
524 I4 location = GetNextTI4(ptr);
525 if (HandleSpecialSymbol (Program, symName)) {
526 // This is the best we can get without
527 // adding too much extra code: Omit the
528 // initialization for all following BSS
529 // sections.
530 if (!(strcmp(symName,SYM_OMIT_BSS_INIT))) {
531 InitializeBSS=FALSE;
532 }
533 // __ld_all_relocs has to be exported from the
534 // first section. So we'll set CanCutRanges to
535 // TRUE for the section it appears in, and
536 // the variable AllRelocs will handle the rest.
537 else if (!(strcmp(symName,SYM_ALL_RELOCS))) {
538 currSection->CanCutRanges = TRUE;
539 AllRelocs = TRUE;
540 }
541 break;
542 }
543 currSymbol = calloc (1, sizeof (SYMBOL));
544 TestMem(currSymbol);
545 currSymbol->Parent = currSection;
546 currSymbol->Location = location;
547 strncpy(currSymbol->Name,symName,MAX_SYM_LEN);
548 currSymbol->Exported = TRUE;
549 InsertSymbol(currSection,currSymbol);
550 break; }
551
552 // References:
553 case AMIGAOS_EXT_REF_ABS1:
554 case AMIGAOS_EXT_REF_ABS2:
555 case AMIGAOS_EXT_REF_ABS4:
556 case AMIGAOS_EXT_REF_REL1:
557 case AMIGAOS_EXT_REF_REL2:
558 case AMIGAOS_EXT_REF_REL4: {
559 // Those are actually relocs in ld-tigcc terms.
560 OFFSET i;
561
562 SIZE relocSize = 0;
563 BOOLEAN relative = FALSE;
564 switch (hunkType) {
565 case AMIGAOS_EXT_REF_REL1:
566 relative = TRUE;
567 case AMIGAOS_EXT_REF_ABS1:
568 relocSize = 1;
569 break;
570 case AMIGAOS_EXT_REF_REL2:
571 relative = TRUE;
572 case AMIGAOS_EXT_REF_ABS2:
573 relocSize = 2;
574 break;
575 case AMIGAOS_EXT_REF_REL4:
576 relative = TRUE;
577 case AMIGAOS_EXT_REF_ABS4:
578 relocSize = 4;
579 break;
580 }
581
582 hunkSize = GetNextTI4(ptr); // hunkSize is the number of relocs here.
583
584 for (i=0; i<(SIZE)hunkSize; i++) {
585 RELOC *newReloc;
586 I4 location = GetNextTI4(ptr);
587 BOOLEAN unoptimizable = FALSE;
588 char *newName = malloc(strlen(symName)+1);
589 TestMem(newName);
590 strcpy(newName,symName);
591 #ifdef AMIGAOS_TIGCC_EXTENSIONS
592 unoptimizable = !!(location&AMIGAOS_RELOC_UNOPTIMIZABLE);
593 location &= ~AMIGAOS_RELOC_UNOPTIMIZABLE;
594 #endif
595 newReloc = calloc (1, sizeof (RELOC));
596 TestMem(newReloc);
597 newReloc->Parent = currSection;
598 newReloc->Location = location;
599 newReloc->Target.SymbolName = newName;
600 newReloc->Size = relocSize;
601 newReloc->Relative = relative;
602 newReloc->Unoptimizable = unoptimizable;
603 if ((OFFSET) (location+relocSize) <= currSection->Size) {
604 if (currSection->Data) {
605 newReloc->FixedOffset = ReadSTI(currSection->Data+location,relocSize);
606 memset(currSection->Data+location,0,relocSize);
607 } else {
608 Warning(FileName,"Adding reloc at 0x%lX in section `%s' without data to symbol `%s'.",(long)location,currSection->SectionSymbol->Name,symName);
609 }
610 } else {
611 Warning(FileName,"Invalid reloc location `0x%lX' in size %ld reference table for origin section `%s' and target symbol `%s'",(long)location,(long)relocSize,currSection->SectionSymbol->Name,symName);
612 }
613
614 // Put this reloc into the linked list
615 InsertReloc(currSection,newReloc);
616 }
617 // The (unused) last copy of the symbol name will be freed below.
618 break; }
619
620 // Other symbol types are never used by A68k.
621 default:
622 FailWithError("Unsupported AmigaOS symbol type `0x%lX'.",(unsigned long)hunkType);
623 break;
624 }
625
626 free(symName);
627 symName = NULL; // Prevent symName from getting freed again.
628 hunkSize = GetNextTI4(ptr);
629 }
630 break;
631
632 case AMIGAOS_HUNK_SYMBOL:
633 // debugging symbol table - contains local (non-exported) symbols,
634 // which are in the object file for debugging purposes only
635
636 // make sure we have a section to put those symbols into
637 if (!currSection)
638 FailWithError("Symbol table hunk without context.");
639
640 hunkSize = GetNextTI4(ptr)<<2;
641 while (hunkSize) {
642 SIZE symSize;
643 I4 location;
644 SYMBOL *symbol;
645 BOOLEAN found=FALSE;
646
647 TestInFile(ptr,I1[hunkSize]);
648 symSize = (hunkSize<MAX_SYM_LEN)?hunkSize:MAX_SYM_LEN;
649
650 for_each(symbol,currSection->Symbols) {
651 if (!strncmp(symbol->Name,ptr,symSize) && !(ptr[symSize])) {
652 found = TRUE;
653 break;
654 }
655 }
656
657 if (found) { // symbol already present - it was already defined as global
658 ptr+=hunkSize;
659
660 // skip location
661 TestInFile(ptr,TI4);
662 ptr+=4;
663 } else {
664 // copy symbol name
665 currSymbol = calloc (1, sizeof (SYMBOL));
666 TestMem(currSymbol);
667 currSymbol->Parent = currSection;
668 strncpy(currSymbol->Name,ptr,symSize);
669 currSymbol->Name[symSize+1]=0;
670 ptr+=hunkSize;
671 // Do NOT handle special symbols specially here! Those symbols are
672 // local and should NOT be interpreted by the linker.
673
674 // copy location
675 location = GetNextTI4(ptr);
676 currSymbol->Location = location;
677
678 //register symbol
679 InsertSymbol(currSection,currSymbol);
680 }
681
682 hunkSize = GetNextTI4(ptr)<<2;
683 }
684 break;
685
686 // The other hunk types are not well-documented or not applicable here, and A68k never generates them anyway.
687 default:
688 FailWithError("Unsupported AmigaOS hunk type `0x%lX'.",(unsigned long)hunkType);
689 break;
690 }
691 }
692
693 // free allocated memory
694 if (hunkName) {
695 Warning(FileName,"Hunk name (`%s') with no corresponding hunk.",hunkName);
696 free(hunkName);
697 }
698 if (relocTargetHunks) {
699 free(relocTargetHunks);
700 }
701
702 return TRUE; // success
703
704 #undef GetNextTI4
705 #undef TestInFile
706 #undef IsInFile
707 #undef TestMem
708 #undef FailWithError
709 #undef Fail
710 }
711
712 #endif /* AMIGAOS_SUPPORT */
713