imp_amig.c 24 KB

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