exp_ndll.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /* exp_ndll.c: Routines to export to a Nostub DLL 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_ndll.h"
  15. #ifdef NOSTUB_DLL_SUPPORT
  16. #include "../manip.h"
  17. #include "../special.h"
  18. // Get the file size needed to export the program into a Nostub DLL file.
  19. // Returns 0 on failure.
  20. // Call this function once to receive necessary error messages.
  21. SIZE GetNostubDLLFileSize (const PROGRAM *Program)
  22. {
  23. // Get a pointer to the main section.
  24. SECTION *MainSection = Program->MainSection;
  25. if (!MainSection)
  26. {
  27. Error (NULL, "No main section.");
  28. return 0;
  29. }
  30. {
  31. // Start with two size bytes and the size of the section.
  32. // Add 2 for the two null bytes at the beginning of the reloc table.
  33. SIZE Size = 2 + MainSection->Size + 2;
  34. if (!(TreeIsEmpty (MainSection->Relocs)))
  35. {
  36. RELOC *Reloc;
  37. // Add the size needed for the relocs.
  38. tree_for_each (Reloc, MainSection->Relocs)
  39. {
  40. // If this can be resolved to a calculator-dependent value, ignore the
  41. // reloc for now.
  42. if (IsPlainCalcBuiltin (Reloc))
  43. continue;
  44. // We can only emit 4-byte absolute relocs.
  45. if (Reloc->Relative || (Reloc->Size != 4))
  46. {
  47. Error (GetFileName (MainSection, Reloc->Location), "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
  48. Size = 0;
  49. }
  50. if (Size)
  51. // A reloc takes 4 bytes: 2 bytes for the location and 2 bytes for the target offset.
  52. Size += 4;
  53. }
  54. }
  55. // Add 1 for the embedded tag byte.
  56. Size ++;
  57. return Size;
  58. }
  59. }
  60. // Export the internal data structures into a Nostub DLL file.
  61. BOOLEAN ExportNostubDLLFile (const PROGRAM *Program, EXP_FILE *File, SIZE FileSize, ProgramCalcs DestCalc ATTRIBUTE_UNUSED)
  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. // Get the section file name for error messages.
  73. SectionFileName = MainSection->FileName;
  74. if (!(MainSection->Data))
  75. FailWithError (SectionFileName, "No section contents.");
  76. // Write out the embedded size.
  77. ExportWriteTI2 (File, FileSize - 2);
  78. // Write out the section contents first.
  79. DataStart = ExportTell (File);
  80. ExportWrite (File, MainSection->Data, MainSection->Size, 1);
  81. // Write out two zero bytes as a separator.
  82. ExportWriteTI2 (File, 0);
  83. if (!(TreeIsEmpty (MainSection->Relocs)))
  84. {
  85. RELOC *Reloc;
  86. // Write out the relocation table.
  87. for (Reloc = TreeLast (MainSection->Relocs); Reloc; Reloc = TreePrev (Reloc))
  88. {
  89. // Get the current file name for error messages.
  90. const char *CurFileName = GetFileName (MainSection, Reloc->Location);
  91. // If this can be resolved to a calculator-dependent value, write the
  92. // value into the section data.
  93. if (EmitCalcBuiltinValue (Reloc, DestCalc, File, FileSize, DataStart))
  94. continue;
  95. // We can only emit relocs with a target symbol in the same section.
  96. if (!(Reloc->Target.Symbol))
  97. FailWithError (CurFileName, "Unresolved reference to `%s'.", Reloc->Target.SymbolName);
  98. if (Reloc->Target.Symbol->Parent != MainSection)
  99. FailWithError (CurFileName, "Cannot emit reloc to `%s' in different section.", Reloc->Target.SymbolName);
  100. // We can only emit 4-byte absolute relocs.
  101. if (Reloc->Relative || (Reloc->Size != 4))
  102. FailWithError (CurFileName, "Cannot emit %ld byte %s reloc to `%s'.", (long) Reloc->Size, Reloc->Relative ? "relative" : "absolute", Reloc->Target.SymbolName);
  103. if (((I2) Reloc->Location) != Reloc->Location)
  104. FailWithError (CurFileName, "Cannot emit reloc outside of limited program range to `%s'.", Reloc->Target.SymbolName);
  105. {
  106. OFFSET TargetLocation = GetLocationOffset (MainSection, &(Reloc->Target)) + Reloc->FixedOffset;
  107. if (((I2) TargetLocation) != TargetLocation)
  108. 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));
  109. // Everything seems to be correct.
  110. ExportWriteTI2 (File, TargetLocation);
  111. ExportWriteTI2 (File, Reloc->Location);
  112. // Increase the statistics.
  113. EmittedRelocCount++;
  114. }
  115. }
  116. }
  117. // Write out the embedded tag byte (ASM_TAG).
  118. ExportWriteTI1 (File, 0xF3);
  119. if ((!(IsEmpty (MainSection->ROMCalls))) && (!(MainSection->ROMCalls.Handled)))
  120. FailWithError (SectionFileName, "ROM calls are not supported in this mode.");
  121. if ((!(IsEmpty (MainSection->RAMCalls))) && (!(MainSection->RAMCalls.Handled)))
  122. FailWithError (SectionFileName, "RAM calls are not supported in this mode.");
  123. if ((!(IsEmpty (MainSection->LibCalls))) && (!(MainSection->LibCalls.Handled)))
  124. FailWithError (SectionFileName, "Library calls are not supported in this mode.");
  125. if (Program->OptimizeInfo->NativeRelocCount < EmittedRelocCount)
  126. Program->OptimizeInfo->NativeRelocCount = EmittedRelocCount;
  127. return TRUE;
  128. #undef FailWithError
  129. }
  130. #endif /* NOSTUB_DLL_SUPPORT */