main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /* main.c: Main entry point for ld-tigcc, handling the command line input
  2. Copyright (C) 2002-2004 Sebastian Reichelt
  3. Copyright (C) 2004 Kevin Kofler
  4. Copyright (C) 2004 Billy Charvet
  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. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  16. #include "generic.h"
  17. #include "intrface.h"
  18. #include "data.h"
  19. #include "manip.h"
  20. #include "constmrg.h"
  21. #include "reorder.h"
  22. #include "formats/ar.h"
  23. #include "import/import.h"
  24. #include "import/imp_ar.h"
  25. #include "export/export.h"
  26. #include "special.h"
  27. #ifdef ENABLE_DUMP
  28. #include "dump.h"
  29. #endif /* ENABLE_DUMP */
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #define RESULT_OK 0
  35. #define RESULT_GENERAL_ERROR 1
  36. #define RESULT_EXPORT_ERROR 2
  37. #define RESULT_STRANGE_ERROR 3
  38. // When compiling a DLL, the caller needs to be able to identify the version
  39. // of the function prototypes.
  40. #ifdef TARGET_DLL
  41. EXP_GET_INTERFACE_VERSION ()
  42. {
  43. return CURRENT_INTERFACE_VERSION;
  44. }
  45. #endif /* TARGET_DLL */
  46. // Main entry point.
  47. #ifdef TARGET_EMBEDDED
  48. ERROR_FUNCTION ErrorFunction;
  49. void Error_Internal (const char *FileName, const char *Text)
  50. {
  51. ErrorFunction (FileName, Text, MT_ERROR);
  52. }
  53. void Warning_Internal (const char *FileName, const char *Text)
  54. {
  55. ErrorFunction (FileName, Text, MT_WARNING);
  56. }
  57. EXP_LINK_FILES ()
  58. {
  59. #define OptInfo OptimizeInfo
  60. #ifdef DATA_VAR_SUPPORT
  61. #define DatVarInfo DataVarInfo
  62. #endif /* DATA_VAR_SUPPORT */
  63. const char **CurFile;
  64. BOOLEAN IsArchive;
  65. #else /* !TARGET_EMBEDDED */
  66. int main (int ArgCount, const char **Args)
  67. {
  68. OPTIMIZE_INFO _OptimizeInfo;
  69. #define OptInfo (&_OptimizeInfo)
  70. #ifdef DATA_VAR_SUPPORT
  71. DATA_VAR_INFO _DataVarInfo;
  72. #define DatVarInfo (&_DataVarInfo)
  73. #endif /* DATA_VAR_SUPPORT */
  74. int CurArg;
  75. BOOLEAN OmitBSSInitialization = FALSE;
  76. #ifdef ENABLE_STATS
  77. BOOLEAN DisplayStats = FALSE;
  78. #endif /* ENABLE_STATS */
  79. #ifdef DATA_VAR_SUPPORT
  80. char DataVarString[MAX_NAME_LEN+1+MAX_NAME_LEN+1];
  81. #endif /* DATA_VAR_SUPPORT */
  82. #endif /* !TARGET_EMBEDDED */
  83. #ifdef ENABLE_DUMP
  84. #define DUMP_COUNT 9
  85. BOOLEAN Dump [DUMP_COUNT] = {[0 ... (DUMP_COUNT - 1)] = FALSE};
  86. #define DoDump(DumpNumber) (_DoDump (DumpNumber, ""))
  87. #define DoSpecialDump(DumpNumber,SpecialText) (_DoDump (DumpNumber, " " SpecialText))
  88. #define _DoDump(DumpNumber,SpecialText) \
  89. ({ if (((DumpNumber) >= 0) && ((DumpNumber) < DUMP_COUNT) && (Dump [(DumpNumber)])) \
  90. { \
  91. printf ("*** DUMP " #DumpNumber SpecialText " ***\n"); \
  92. DumpProgram (stdout, NULL, &Program); \
  93. printf ("\n"); \
  94. } })
  95. #else /* !ENABLE_DUMP */
  96. #define DoDump(DumpNumber) ((void) 0)
  97. #define DoSpecialDump(DumpNumber,SpecialText) ((void) 0)
  98. #endif /* !ENABLE_DUMP */
  99. int Result = RESULT_GENERAL_ERROR;
  100. PROGRAM Program;
  101. // Check the sizes of basic integer types.
  102. if (sizeof (I1) != 1 || sizeof (I2) != 2 || sizeof (I4) != 4 || sizeof (SI1) != 1 || sizeof (SI2) != 2 || sizeof (SI4) != 4 || sizeof (OFFSET) < sizeof (SI4))
  103. {
  104. Error (NULL, "Generic type size error!");
  105. return RESULT_STRANGE_ERROR;
  106. }
  107. // Initialize.
  108. memset (&Program, 0, sizeof (Program));
  109. Program.EntryPoint.SymbolName = "__entry_point";
  110. #ifdef TARGET_EMBEDDED
  111. ErrorFunction = ErrorMessage;
  112. if (NativeMode)
  113. Program.Type = PT_NATIVE;
  114. #else /* !TARGET_EMBEDDED */
  115. memset (&_OptimizeInfo, 0, sizeof (_OptimizeInfo));
  116. #ifdef DATA_VAR_SUPPORT
  117. memset (&_DataVarInfo, 0, sizeof (_DataVarInfo));
  118. #endif /* DATA_VAR_SUPPORT */
  119. memset (ProgramName, 0, MAX_NAME_LEN + 1);
  120. memset (ProgramFolder, 0, MAX_NAME_LEN + 1);
  121. strcpy (ProgramFolder, "main");
  122. #endif /* !TARGET_EMBEDDED */
  123. Program.OptimizeInfo = OptInfo;
  124. #ifdef DATA_VAR_SUPPORT
  125. Program.DataVarInfo = DatVarInfo;
  126. #endif /* DATA_VAR_SUPPORT */
  127. #ifdef TARGET_EMBEDDED
  128. if (Fargo)
  129. {
  130. #ifdef FARGO_SUPPORT
  131. Program.Type = PT_FARGO;
  132. Program.Calcs |= CALC_TI92;
  133. Warning (NULL, "Fargo support in TIGCC is experimental.");
  134. #else /* !FARGO_SUPPORT */
  135. Error (NULL, "Fargo support is not compiled in.");
  136. goto Cleanup;
  137. #endif /* !FARGO_SUPPORT */
  138. }
  139. if (FlashOS)
  140. {
  141. #ifdef FLASH_OS_SUPPORT
  142. Program.Type = PT_FLASH_OS;
  143. Warning (NULL, "Flash OS support in TIGCC is experimental.");
  144. #else /* !FLASH_OS_SUPPORT */
  145. Error (NULL, "Flash OS support is not compiled in.");
  146. goto Cleanup;
  147. #endif /* !FLASH_OS_SUPPORT */
  148. }
  149. CurFile = ObjectFiles;
  150. IsArchive = FALSE;
  151. while (CurFile && (*CurFile))
  152. {
  153. FILE *File = fopen (*CurFile, "rb");
  154. if (File)
  155. {
  156. SIZE Size;
  157. fseek (File, 0, SEEK_END);
  158. Size = ftell (File);
  159. rewind (File);
  160. {
  161. I1 *Data = malloc (Size);
  162. if (Data)
  163. {
  164. if (fread (Data, Size, 1, File) == 1)
  165. {
  166. if (IsArchive)
  167. AddArchiveFile (&Program, Data, Size, *CurFile);
  168. else
  169. ImportObjectFile (&Program, Data, Size, *CurFile);
  170. }
  171. else
  172. Error (*CurFile, "Unable to read file.");
  173. if (!IsArchive)
  174. free (Data);
  175. }
  176. else
  177. Error (*CurFile, "Not enough memory to load file.");
  178. }
  179. fclose (File);
  180. }
  181. else
  182. Error (*CurFile, "Unable to open file.");
  183. if ((!IsArchive) && (!(*(CurFile + 1))))
  184. {
  185. CurFile = ArchiveFiles;
  186. IsArchive = TRUE;
  187. }
  188. else
  189. CurFile++;
  190. }
  191. #else /* !TARGET_EMBEDDED */
  192. #include "main_opt.inc"
  193. #endif /* !TARGET_EMBEDDED */
  194. if (IsEmpty (Program.Sections))
  195. Error (NULL, "Cannot create empty program.");
  196. else
  197. {
  198. DoDump (0);
  199. // Connect all relocs to the appropriate symbols, or convert them into
  200. // ROM/RAM calls. Also import objects from archives.
  201. // Report all unresolved references.
  202. if (ResolveRelocs (&Program, TRUE))
  203. {
  204. DoDump (1);
  205. // Merge all zero-data and uninitialized sections.
  206. Program.BSSSection = MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE);
  207. // As a dirty trick, allow the caller to skip the BSS
  208. // initialization entirely.
  209. if (Program.BSSSection && OmitBSSInitialization)
  210. Program.BSSSection->Initialized = FALSE;
  211. // Extract, merge, and mark constructor and destructor sections.
  212. CreateSectionMarkers (&(Program.Constructors), MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE));
  213. CreateSectionMarkers (&(Program.Destructors), MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE));
  214. #ifdef DATA_VAR_SUPPORT
  215. // If we want a separate data variable, merge all data
  216. // sections.
  217. if (DatVarInfo->Name)
  218. {
  219. Program.DataSection = MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE);
  220. // Mark the section as "handled" so it will not be merged
  221. // with code.
  222. if (Program.DataSection)
  223. Program.DataSection->Handled = TRUE;
  224. else
  225. Warning (NULL, "No data to put into external variable.");
  226. }
  227. #endif /* DATA_VAR_SUPPORT */
  228. DoDump (2);
  229. // Create all global imports needed by this program.
  230. CreateSpecialGlobalImports (&Program);
  231. DoDump (3);
  232. // Resolve all remaining global imports. Usually, global imports
  233. // are processed directly, but if a symbol contains an inverted
  234. // condition, we have to wait until we really know that no such
  235. // global import exists.
  236. ResolveRemainingGlobalImports (&Program);
  237. // Resolve the relocs from the newly imported archive members.
  238. if (ResolveRelocs (&Program, TRUE))
  239. {
  240. // No more startup sections may be added.
  241. // So the program entry point is fixed from now on.
  242. {
  243. SECTION *FirstSection = GetFirst (Program.Sections);
  244. if (FirstSection)
  245. {
  246. Program.EntryPoint.Symbol = FirstSection->SectionSymbol;
  247. Program.EntryPoint.SymbolName = FirstSection->SectionSymbol->Name;
  248. #ifdef FARGO_SUPPORT
  249. // Fargo programs use the location in front
  250. // of the two size bytes as the entry point.
  251. if (Program.Type == PT_FARGO)
  252. Program.EntryPoint.Offset -= 2;
  253. #endif /* FARGO_SUPPORT */
  254. }
  255. }
  256. DoDump (4);
  257. // Now that all relocs have been resolved, there is no chance
  258. // that some previously unknown archive member will add new imports.
  259. CheckAllGlobalImports (&Program);
  260. if (OptInfo->OptimizeRelocs)
  261. {
  262. // Optimize relocs. This should not have any effect on the program.
  263. OptimizeRelocs (&Program);
  264. DoSpecialDump (4, "(optimized)");
  265. }
  266. if (OptInfo->RemoveUnused && (!(Program.Frozen)))
  267. {
  268. // Remove unreferenced sections.
  269. RemoveUnusedSections (&Program);
  270. DoSpecialDump (4, "(cut)");
  271. }
  272. if (OptInfo->MergeConstants && (!(Program.Frozen)))
  273. {
  274. // Merge constants.
  275. MergeConstants (&Program);
  276. DoSpecialDump (4, "(const-merged)");
  277. }
  278. if (OptInfo->ReorderSections && (!(Program.Frozen)))
  279. {
  280. // Reorder sections.
  281. ReorderSections (&Program);
  282. DoSpecialDump (4, "(reordered)");
  283. }
  284. #ifdef FLASH_OS_SUPPORT
  285. if (Program.Type == PT_FLASH_OS)
  286. {
  287. // Flash OS export: merge startup and normal sections separately.
  288. // The resulting two parts are merged later, padding the first
  289. // part to the full 24 KB of the OS startup area (base 1)
  290. // + the 8 KB corresponding to the read protected FlashROM
  291. // area.
  292. // Thus, the startup sections end up in the OS startup area
  293. // (base 1) and the non-startup areas end up in the OS main
  294. // area (base 2), the big OS code part.
  295. // Merge all startup sections.
  296. MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE);
  297. // Merge all normal sections.
  298. MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE);
  299. }
  300. #endif /* FLASH_OS_SUPPORT */
  301. // Merge all initialized sections.
  302. Program.MainSection = MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
  303. // Merge all unhandled sections.
  304. Program.MainSection = MergeAllSections (&Program, Program.MainSection, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE);
  305. // Record the size of the BSS section.
  306. if (Program.BSSSection)
  307. OptInfo->BSSSize = Program.BSSSection->Size;
  308. if (Program.MainSection && Program.Library && (Program.MainSection->StartupNumber > 0))
  309. Warning (Program.MainSection->FileName, "Library only contains program startup sections.");
  310. DoDump (5);
  311. // Fix the code (if that is still possible).
  312. FixCode (&Program);
  313. DoDump (6);
  314. // Resolve the relocs pointing to built-in symbols.
  315. Program.ResolveAllBuiltins = TRUE;
  316. // Resolve requested automatic insertions.
  317. if (ResolveRelocs (&Program, TRUE))
  318. {
  319. DoDump (7);
  320. // Do one more optimization pass for relocs to automatic insertions.
  321. FixCode (&Program);
  322. // Remove relocs where possible.
  323. if (FixupRelativeRelocs (&Program))
  324. {
  325. DoDump (8);
  326. if (Program.Calcs)
  327. {
  328. // Export the program to the appropriate files.
  329. if (ExportProgram (&Program, GetOutputFile, FinalizeOutputFile))
  330. {
  331. Result = RESULT_OK;
  332. #ifndef TARGET_EMBEDDED
  333. #ifdef ENABLE_STATS
  334. #include "main_vbs.inc"
  335. #endif /* ENABLE_STATS */
  336. #endif /* !TARGET_EMBEDDED */
  337. }
  338. else
  339. Result = RESULT_EXPORT_ERROR;
  340. }
  341. else
  342. Error (NULL, "No target calculators specified.");
  343. }
  344. }
  345. }
  346. }
  347. }
  348. Cleanup: ATTRIBUTE_UNUSED
  349. // Final Cleanup.
  350. FreeProgram (&Program);
  351. return Result;
  352. }