exp_tios.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /* exp_tios.c: Routines to export to a TIOS file
  2. Copyright (C) 2002-2003 Sebastian Reichelt
  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 "exp_tios.h"
  15. #ifdef TIOS_SUPPORT
  16. #include <string.h>
  17. #include "../manip.h"
  18. #include "../special.h"
  19. #include "../formats/tios.h"
  20. // Get the file size needed to export the program into a TIOS file.
  21. // Returns 0 on failure.
  22. // Call this function once to receive necessary error messages.
  23. SIZE GetTIOSFileSize (const PROGRAM *Program)
  24. {
  25. // Get a pointer to the main section.
  26. SECTION *MainSection = Program->MainSection;
  27. if (!MainSection)
  28. {
  29. Error (NULL, "No main section.");
  30. return 0;
  31. }
  32. {
  33. // Start with the size of the section.
  34. // Add 2 for the two null bytes at the beginning of the reloc table.
  35. SIZE Size = MainSection->Size + 2;
  36. if (!(IsEmpty (MainSection->Relocs)))
  37. {
  38. RELOC *Reloc;
  39. // Add the size needed for the relocs.
  40. for_each (Reloc, MainSection->Relocs)
  41. {
  42. // If this can be resolved to a calculator-dependent value, ignore the
  43. // reloc for now.
  44. if (IsPlainCalcBuiltin (Reloc))
  45. continue;
  46. // We can only emit 4-byte absolute relocs.
  47. if (Reloc->Relative || (Reloc->Size != 4))
  48. {
  49. Error (GetFileName (MainSection, Reloc->Location), "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
  50. Size = 0;
  51. }
  52. if (Size)
  53. // A reloc takes 4 bytes: 2 bytes for the location and 2 bytes for the target offset.
  54. Size += 4;
  55. }
  56. }
  57. return Size;
  58. }
  59. }
  60. // Export the internal data structures into a TIOS file.
  61. BOOLEAN ExportTIOSFile (const PROGRAM *Program, EXP_FILE *File, SIZE FileSize, ProgramCalcs DestCalc)
  62. {
  63. // A simple macro to make the code more readable.
  64. #define FailWithError(Err...) ({ Error (Err); return FALSE; })
  65. const char *SectionFileName = NULL;
  66. OFFSET DataStart = 0;
  67. COUNT EmittedRelocCount = 0;
  68. // Get a pointer to the main section.
  69. SECTION *MainSection = Program->MainSection;
  70. if (!MainSection)
  71. FailWithError (NULL, "No main section.");
  72. SectionFileName = MainSection->FileName;
  73. // In nostub mode, execution simply starts at the beginning of
  74. // the first section. But ideally, startup code should always be
  75. // marked as such. When merging sections, the destination startup
  76. // number is kept, so in the end, the complete code is marked as
  77. // a startup section (which makes sense; it is startable).
  78. if (!(MainSection->StartupNumber || (Program->Type == PT_NOSTUB)))
  79. FailWithError (SectionFileName, "No startup section(s) defined.");
  80. if (!(MainSection->Data))
  81. FailWithError (SectionFileName, "No section contents.");
  82. // Write out the section contents first.
  83. DataStart = ExportTell (File);
  84. ExportWrite (File, MainSection->Data, MainSection->Size, 1);
  85. // Write out two zero bytes as a separator.
  86. ExportWriteTI2 (File, 0);
  87. if (!(IsEmpty (MainSection->Relocs)))
  88. {
  89. RELOC *Reloc;
  90. // Write out the relocation table.
  91. for (Reloc = GetLast (MainSection->Relocs); Reloc; Reloc = GetPrev (Reloc))
  92. {
  93. // Get the current file name for error messages.
  94. const char *CurFileName = GetFileName (MainSection, Reloc->Location);
  95. // If this can be resolved to a calculator-dependent value, write the
  96. // value into the section data.
  97. if (EmitCalcBuiltinValue (Reloc, DestCalc, File, FileSize, DataStart))
  98. continue;
  99. // We can only emit relocs with a target symbol in the same section.
  100. if (!(Reloc->Target.Symbol))
  101. FailWithError (CurFileName, "Unresolved reference to `%s'.", Reloc->Target.SymbolName);
  102. if (Reloc->Target.Symbol->Parent != MainSection)
  103. FailWithError (CurFileName, "Cannot emit reloc to `%s' in different section.", Reloc->Target.SymbolName);
  104. // We can only emit 4-byte absolute relocs.
  105. if (Reloc->Relative || (Reloc->Size != 4))
  106. FailWithError (CurFileName, "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
  107. if (((I2) Reloc->Location) != Reloc->Location)
  108. FailWithError (CurFileName, "Cannot emit reloc outside of limited program range to `%s'.", Reloc->Target.SymbolName);
  109. {
  110. OFFSET TargetLocation = GetLocationOffset (MainSection, &(Reloc->Target)) + Reloc->FixedOffset;
  111. if (((I2) TargetLocation) != TargetLocation)
  112. FailWithError (CurFileName, "Cannot emit reloc to `%s' (Offset %ld; Location 0x%lX) outside of limited program range.", Reloc->Target.SymbolName, (long) (Reloc->Target.Offset + Reloc->FixedOffset), (long) (TargetLocation));
  113. // Everything seems to be correct.
  114. ExportWriteTI2 (File, TargetLocation);
  115. ExportWriteTI2 (File, Reloc->Location);
  116. // Increase the statistics.
  117. EmittedRelocCount++;
  118. }
  119. }
  120. }
  121. if ((!(IsEmpty (MainSection->ROMCalls))) && (!(MainSection->ROMCalls.Handled)))
  122. FailWithError (SectionFileName, "ROM calls are not supported in this mode.");
  123. if ((!(IsEmpty (MainSection->RAMCalls))) && (!(MainSection->RAMCalls.Handled)))
  124. FailWithError (SectionFileName, "RAM calls are not supported in this mode.");
  125. if ((!(IsEmpty (MainSection->LibCalls))) && (!(MainSection->LibCalls.Handled)))
  126. FailWithError (SectionFileName, "Library calls are not supported in this mode.");
  127. if (Program->OptimizeInfo->NativeRelocCount < EmittedRelocCount)
  128. Program->OptimizeInfo->NativeRelocCount = EmittedRelocCount;
  129. return TRUE;
  130. #undef FailWithError
  131. }
  132. #ifdef PUCRUNCH_SUPPORT
  133. #include "pucrunch.h"
  134. // Export the internal data structures into a packed TIOS file.
  135. BOOLEAN ExportPackedTIOSFile (const PROGRAM *Program, EXP_FILE *File, SIZE FileSize, ProgramCalcs DestCalc)
  136. {
  137. // Some macros to make the code more readable.
  138. #define FailWithError(Err...) ({ Error (Err); return FALSE; })
  139. #define BufferWrite(P,L,C) (memcpy (Buffer + CurPos, P, (L) * (C)), CurPos += (L) * (C))
  140. #define BufferWriteTI2(D) ({ WriteTI2 (*((TI2 *) (Buffer + CurPos)), D); CurPos += 2; })
  141. const char *SectionFileName = NULL;
  142. OFFSET DataStart = 0;
  143. COUNT EmittedRelocCount = 0;
  144. // Calculate the size needed for the two size bytes and the
  145. // tag.
  146. SIZE VarFileSize = 2 + FileSize + 1;
  147. I1 Buffer[VarFileSize];
  148. OFFSET CurPos = 0;
  149. // Write out the 2 size bytes.
  150. BufferWriteTI2 (VarFileSize - 2);
  151. // Get a pointer to the main section.
  152. SECTION *MainSection = Program->MainSection;
  153. if (!MainSection)
  154. FailWithError (NULL, "No main section.");
  155. SectionFileName = MainSection->FileName;
  156. // In nostub mode, execution simply starts at the beginning of
  157. // the first section. But ideally, startup code should always be
  158. // marked as such. When merging sections, the destination startup
  159. // number is kept, so in the end, the complete code is marked as
  160. // a startup section (which makes sense; it is startable).
  161. if (!(MainSection->StartupNumber || (Program->Type == PT_NOSTUB)))
  162. FailWithError (SectionFileName, "No startup section(s) defined.");
  163. if (!(MainSection->Data))
  164. FailWithError (SectionFileName, "No section contents.");
  165. // Write out the section contents first.
  166. DataStart = CurPos;
  167. BufferWrite (MainSection->Data, MainSection->Size, 1);
  168. // Write out two zero bytes as a separator.
  169. BufferWriteTI2 (0);
  170. if (!(IsEmpty (MainSection->Relocs)))
  171. {
  172. RELOC *Reloc;
  173. // Write out the relocation table.
  174. for (Reloc = GetLast (MainSection->Relocs); Reloc; Reloc = GetPrev (Reloc))
  175. {
  176. // Get the current file name for error messages.
  177. const char *CurFileName = GetFileName (MainSection, Reloc->Location);
  178. // If this can be resolved to a calculator-dependent value, write the
  179. // value into the section data.
  180. if (EmitCalcBuiltinValueBuf (Reloc, DestCalc, Buffer, FileSize, DataStart))
  181. continue;
  182. // We can only emit relocs with a target symbol in the same section.
  183. if (!(Reloc->Target.Symbol))
  184. FailWithError (CurFileName, "Unresolved reference to `%s'.", Reloc->Target.SymbolName);
  185. if (Reloc->Target.Symbol->Parent != MainSection)
  186. FailWithError (CurFileName, "Cannot emit reloc to `%s' in different section.", Reloc->Target.SymbolName);
  187. // We can only emit 4-byte absolute relocs.
  188. if (Reloc->Relative || (Reloc->Size != 4))
  189. FailWithError (CurFileName, "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
  190. if (((I2) Reloc->Location) != Reloc->Location)
  191. FailWithError (CurFileName, "Cannot emit reloc outside of limited program range to `%s'.", Reloc->Target.SymbolName);
  192. {
  193. OFFSET TargetLocation = GetLocationOffset (MainSection, &(Reloc->Target)) + Reloc->FixedOffset;
  194. if (((I2) TargetLocation) != TargetLocation)
  195. FailWithError (CurFileName, "Cannot emit reloc to `%s' (Offset %ld; Location 0x%lX) outside of limited program range.", Reloc->Target.SymbolName, (long) (Reloc->Target.Offset + Reloc->FixedOffset), (long) (TargetLocation));
  196. // Everything seems to be correct.
  197. BufferWriteTI2 (TargetLocation);
  198. BufferWriteTI2 (Reloc->Location);
  199. // Increase the statistics.
  200. EmittedRelocCount++;
  201. }
  202. }
  203. }
  204. if ((!(IsEmpty (MainSection->ROMCalls))) && (!(MainSection->ROMCalls.Handled)))
  205. FailWithError (SectionFileName, "ROM calls are not supported in this mode.");
  206. if ((!(IsEmpty (MainSection->RAMCalls))) && (!(MainSection->RAMCalls.Handled)))
  207. FailWithError (SectionFileName, "RAM calls are not supported in this mode.");
  208. if ((!(IsEmpty (MainSection->LibCalls))) && (!(MainSection->LibCalls.Handled)))
  209. FailWithError (SectionFileName, "Library calls are not supported in this mode.");
  210. // Write out the final ASM tag.
  211. Buffer[CurPos] = TIOS_TAG_ASM;
  212. if (Program->OptimizeInfo->NativeRelocCount < EmittedRelocCount)
  213. Program->OptimizeInfo->NativeRelocCount = EmittedRelocCount;
  214. // Now compress the buffer and write it out to the file.
  215. return !TTPack(0, VarFileSize, Buffer, File);
  216. #undef FailWithError
  217. }
  218. #endif /* PUCRUNCH_SUPPORT */
  219. #endif /* TIOS_SUPPORT */