main.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  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-2005 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 "gcunused.h"
  22. #include "reorder.h"
  23. #include "formats/ar.h"
  24. #include "import/import.h"
  25. #include "import/imp_ar.h"
  26. #include "export/export.h"
  27. #include "special.h"
  28. #ifdef ENABLE_DUMP
  29. #include "dump.h"
  30. #endif /* ENABLE_DUMP */
  31. #include <stdlib.h>
  32. #include <stdio.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #define RESULT_OK 0
  36. #define RESULT_GENERAL_ERROR 1
  37. #define RESULT_EXPORT_ERROR 2
  38. #define RESULT_STRANGE_ERROR 3
  39. // When compiling a DLL, the caller needs to be able to identify the version
  40. // of the function prototypes.
  41. #ifdef TARGET_DLL
  42. EXP_GET_INTERFACE_VERSION ()
  43. {
  44. return CURRENT_INTERFACE_VERSION;
  45. }
  46. #endif /* TARGET_DLL */
  47. // Main entry point.
  48. #ifdef TARGET_EMBEDDED
  49. ERROR_FUNCTION ErrorFunction;
  50. void Error_Internal (const char *FileName, const char *Text)
  51. {
  52. ErrorFunction (FileName, Text, MT_ERROR);
  53. }
  54. void Warning_Internal (const char *FileName, const char *Text)
  55. {
  56. ErrorFunction (FileName, Text, MT_WARNING);
  57. }
  58. EXP_LINK_FILES ()
  59. {
  60. #define OptInfo OptimizeInfo
  61. #ifdef DATA_VAR_SUPPORT
  62. #define DatVarInfo DataVarInfo
  63. #endif /* DATA_VAR_SUPPORT */
  64. const char **CurFile;
  65. BOOLEAN IsArchive;
  66. #else /* !TARGET_EMBEDDED */
  67. static void DecodeOnCalcName(char *Dest, const char *Src)
  68. {
  69. COUNT Count = 0;
  70. do {
  71. if (*Src == '%'
  72. && ((Src[1] >= '0' && Src[1] <= '9')
  73. || (Src[1] >= 'A' && Src[1] <= 'F')
  74. || (Src[1] >= 'a' && Src[1] <= 'f'))
  75. && ((Src[2] >= '0' && Src[2] <= '9')
  76. || (Src[2] >= 'A' && Src[2] <= 'F')
  77. || (Src[2] >= 'a' && Src[2] <= 'f')))
  78. {
  79. char Src1 = *(++Src);
  80. char Src2 = *(++Src);
  81. if (Src1 >= '0' && Src1 <= '9')
  82. Src1 -= '0';
  83. else if (Src1 >= 'A' && Src1 <= 'F')
  84. Src1 += (10 - 'A');
  85. else if (Src1 >= 'a' && Src1 <= 'f')
  86. Src1 += (10 - 'a');
  87. if (Src2 >= '0' && Src2 <= '9')
  88. Src2 -= '0';
  89. else if (Src2 >= 'A' && Src2 <= 'F')
  90. Src2 += (10 - 'A');
  91. else if (Src2 >= 'a' && Src2 <= 'f')
  92. Src2 += (10 - 'a');
  93. *(Dest++) = (Src1 << 4) + Src2;
  94. Src++;
  95. }
  96. else if (*Src)
  97. *(Dest++) = *(Src++);
  98. else
  99. break;
  100. } while (++Count < MAX_NAME_LEN);
  101. }
  102. // Maps uppercase characters in the calculator charset to lowercase.
  103. // This matches AMS conversion rules, so Greek letters are not converted.
  104. static char CalcTolower(char Lower)
  105. {
  106. unsigned char c = Lower;
  107. if ((c >= 'A' && c <= 'Z')
  108. || (c >= 192 && c <= 222 && c != 215))
  109. c += 32;
  110. return c;
  111. }
  112. int main (int ArgCount, const char **Args)
  113. {
  114. OPTIMIZE_INFO _OptimizeInfo;
  115. #define OptInfo (&_OptimizeInfo)
  116. #ifdef DATA_VAR_SUPPORT
  117. DATA_VAR_INFO _DataVarInfo;
  118. #define DatVarInfo (&_DataVarInfo)
  119. #endif /* DATA_VAR_SUPPORT */
  120. int CurArg;
  121. BOOLEAN OmitBSSInitialization = FALSE;
  122. #ifdef ENABLE_STATS
  123. BOOLEAN DisplayStats = FALSE;
  124. #endif /* ENABLE_STATS */
  125. #ifdef DATA_VAR_SUPPORT
  126. char DataVarString[MAX_NAME_LEN+1+MAX_NAME_LEN+1];
  127. #endif /* DATA_VAR_SUPPORT */
  128. #endif /* !TARGET_EMBEDDED */
  129. #ifdef ENABLE_DUMP
  130. #define DUMP_COUNT 9
  131. BOOLEAN Dump [DUMP_COUNT] = {[0 ... (DUMP_COUNT - 1)] = FALSE};
  132. #define DoDump(DumpNumber) (_DoDump (DumpNumber, ""))
  133. #define DoSpecialDump(DumpNumber,SpecialText) (_DoDump (DumpNumber, " " SpecialText))
  134. #define _DoDump(DumpNumber,SpecialText) \
  135. ({ if (((DumpNumber) >= 0) && ((DumpNumber) < DUMP_COUNT) && (Dump [(DumpNumber)])) \
  136. { \
  137. printf ("*** DUMP " #DumpNumber SpecialText " ***\n"); \
  138. DumpProgram (stdout, NULL, &Program); \
  139. printf ("\n"); \
  140. } })
  141. #else /* !ENABLE_DUMP */
  142. #define DoDump(DumpNumber) ((void) 0)
  143. #define DoSpecialDump(DumpNumber,SpecialText) ((void) 0)
  144. #endif /* !ENABLE_DUMP */
  145. int Result = RESULT_GENERAL_ERROR;
  146. PROGRAM Program;
  147. // Check the sizes of basic integer types.
  148. if (sizeof (I1) != 1 || sizeof (I2) != 2 || sizeof (I4) != 4 || sizeof (SI1) != 1 || sizeof (SI2) != 2 || sizeof (SI4) != 4 || sizeof (OFFSET) < sizeof (SI4))
  149. {
  150. Error (NULL, "Generic type size error!");
  151. return RESULT_STRANGE_ERROR;
  152. }
  153. // Initialize.
  154. memset (&Program, 0, sizeof (Program));
  155. Program.EntryPoint.SymbolName = "__entry_point";
  156. #ifdef TARGET_EMBEDDED
  157. ErrorFunction = ErrorMessage;
  158. if (NativeMode)
  159. Program.Type = PT_NATIVE;
  160. #else /* !TARGET_EMBEDDED */
  161. memset (&_OptimizeInfo, 0, sizeof (_OptimizeInfo));
  162. #ifdef DATA_VAR_SUPPORT
  163. memset (&_DataVarInfo, 0, sizeof (_DataVarInfo));
  164. #endif /* DATA_VAR_SUPPORT */
  165. memset (ProgramName, 0, MAX_NAME_LEN + 1);
  166. memset (ProgramFolder, 0, MAX_NAME_LEN + 1);
  167. strcpy (ProgramFolder, "main");
  168. #endif /* !TARGET_EMBEDDED */
  169. Program.OptimizeInfo = OptInfo;
  170. #ifdef DATA_VAR_SUPPORT
  171. Program.DataVarInfo = DatVarInfo;
  172. #endif /* DATA_VAR_SUPPORT */
  173. #ifdef TARGET_EMBEDDED
  174. if (Fargo)
  175. {
  176. #ifdef FARGO_SUPPORT
  177. Program.Type = PT_FARGO;
  178. Program.Calcs |= CALC_TI92;
  179. Warning (NULL, "Fargo support in TIGCC is experimental.");
  180. #else /* !FARGO_SUPPORT */
  181. Error (NULL, "Fargo support is not compiled in.");
  182. goto Cleanup;
  183. #endif /* !FARGO_SUPPORT */
  184. }
  185. if (FlashOS)
  186. {
  187. #ifdef FLASH_OS_SUPPORT
  188. Program.Type = PT_FLASH_OS;
  189. Warning (NULL, "Flash OS support in TIGCC is experimental.");
  190. #else /* !FLASH_OS_SUPPORT */
  191. Error (NULL, "Flash OS support is not compiled in.");
  192. goto Cleanup;
  193. #endif /* !FLASH_OS_SUPPORT */
  194. }
  195. CurFile = ObjectFiles;
  196. IsArchive = FALSE;
  197. while (CurFile && (*CurFile))
  198. {
  199. FILE *File = fopen (*CurFile, "rb");
  200. if (File)
  201. {
  202. SIZE Size;
  203. fseek (File, 0, SEEK_END);
  204. Size = ftell (File);
  205. rewind (File);
  206. {
  207. I1 *Data = malloc (Size);
  208. if (Data)
  209. {
  210. if (fread (Data, Size, 1, File) == 1)
  211. {
  212. if (IsArchive)
  213. AddArchiveFile (&Program, Data, Size, *CurFile);
  214. else
  215. ImportObjectFile (&Program, Data, Size, *CurFile);
  216. }
  217. else
  218. Error (*CurFile, "Unable to read file.");
  219. if (!IsArchive)
  220. free (Data);
  221. }
  222. else
  223. Error (*CurFile, "Not enough memory to load file.");
  224. }
  225. fclose (File);
  226. }
  227. else
  228. Error (*CurFile, "Unable to open file.");
  229. if ((!IsArchive) && (!(*(CurFile + 1))))
  230. {
  231. CurFile = ArchiveFiles;
  232. IsArchive = TRUE;
  233. }
  234. else
  235. CurFile++;
  236. }
  237. #else /* !TARGET_EMBEDDED */
  238. #include "main_opt.inc"
  239. #endif /* !TARGET_EMBEDDED */
  240. if (IsEmpty (Program.Sections))
  241. Error (NULL, "Cannot create empty program.");
  242. else
  243. {
  244. DoDump (0);
  245. // Connect all relocs to the appropriate symbols, or convert them into
  246. // ROM/RAM calls. Also import objects from archives.
  247. // Report all unresolved references.
  248. if (ResolveRelocs (&Program, TRUE))
  249. {
  250. DoDump (1);
  251. // Merge all zero-data and uninitialized sections.
  252. Program.BSSSection = MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, DI_NONE);
  253. // As a dirty trick, allow the caller to skip the BSS
  254. // initialization entirely.
  255. if (Program.BSSSection && OmitBSSInitialization)
  256. Program.BSSSection->Initialized = FALSE;
  257. // Extract, merge, and mark constructor and destructor sections.
  258. CreateSectionMarkers (&(Program.Constructors), MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, TRUE, TRUE, DI_NONE));
  259. CreateSectionMarkers (&(Program.Destructors), MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, DI_NONE));
  260. #ifdef DEBUGGING_INFO_SUPPORT
  261. // If we want debugging information, merge all debugging information
  262. // sections of each type.
  263. {
  264. DebuggingInfoTypes i;
  265. for (i = 1; i < DI_LAST; i++)
  266. {
  267. Program.DebuggingInfoSection[i] = MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, i + 1);
  268. if (Program.DebuggingInfoSection[i])
  269. {
  270. Program.DebuggingInfoSection[i]->Handled = TRUE;
  271. Program.HaveDebuggingInfo = TRUE;
  272. }
  273. }
  274. }
  275. #endif /* DEBUGGING_INFO_SUPPORT */
  276. #ifdef DATA_VAR_SUPPORT
  277. // If we want a separate data variable, merge all data
  278. // sections.
  279. if (DatVarInfo->Name)
  280. {
  281. if (OptInfo->RemoveUnused && (!(Program.Frozen)))
  282. {
  283. // Mark the section containing __main as referenced.
  284. MarkMainSection (&Program);
  285. // Remove unreferenced sections now, before constant merging
  286. // and section merging make it impossible.
  287. RemoveUnusedSections (&Program);
  288. // Reset the Referenced flags so we can do another GC pass
  289. // when the imports are done.
  290. ResetReferencedFlags (&Program);
  291. #ifdef DEBUGGING_INFO_SUPPORT
  292. if (Program.HaveDebuggingInfo)
  293. {
  294. // Merge all unused sections into a .deleted section.
  295. Program.DebuggingInfoSection[0] = MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1);
  296. if (Program.DebuggingInfoSection[0])
  297. Program.DebuggingInfoSection[0]->Handled = TRUE;
  298. }
  299. #endif /* DEBUGGING_INFO_SUPPORT */
  300. DoSpecialDump (1, "(early-cut)");
  301. }
  302. if (OptInfo->MergeConstants && (!(Program.Frozen)))
  303. {
  304. // Merge constants now, as we can't do it anymore after
  305. // the data variable has been built.
  306. MergeConstants (&Program);
  307. DoSpecialDump (1, "(const-merged)");
  308. }
  309. Program.DataSection = MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, TRUE, TRUE, FALSE, DI_NONE);
  310. // Mark the section as "handled" so it will not be merged
  311. // with code.
  312. if (Program.DataSection)
  313. Program.DataSection->Handled = TRUE;
  314. else
  315. Warning (NULL, "No data to put into external variable.");
  316. }
  317. #endif /* DATA_VAR_SUPPORT */
  318. DoDump (2);
  319. // Create all global imports needed by this program.
  320. CreateSpecialGlobalImports (&Program);
  321. DoDump (3);
  322. // Resolve all remaining global imports. Usually, global imports
  323. // are processed directly, but if a symbol contains an inverted
  324. // condition, we have to wait until we really know that no such
  325. // global import exists.
  326. ResolveRemainingGlobalImports (&Program);
  327. // Resolve the relocs from the newly imported archive members.
  328. if (ResolveRelocs (&Program, TRUE))
  329. {
  330. // No more startup sections may be added.
  331. // So the program entry point is fixed from now on.
  332. {
  333. SECTION *FirstSection = GetFirst (Program.Sections);
  334. if (FirstSection)
  335. {
  336. Program.EntryPoint.Symbol = FirstSection->SectionSymbol;
  337. Program.EntryPoint.SymbolName = FirstSection->SectionSymbol->Name;
  338. #ifdef FARGO_SUPPORT
  339. // Fargo programs use the location in front
  340. // of the two size bytes as the entry point.
  341. if (Program.Type == PT_FARGO)
  342. Program.EntryPoint.Offset -= 2;
  343. #endif /* FARGO_SUPPORT */
  344. }
  345. }
  346. DoDump (4);
  347. // Now that all relocs have been resolved, there is no chance
  348. // that some previously unknown archive member will add new imports.
  349. CheckAllGlobalImports (&Program);
  350. if (OptInfo->OptimizeRelocs)
  351. {
  352. // Optimize relocs. This should not have any effect on the program.
  353. OptimizeRelocs (&Program);
  354. DoSpecialDump (4, "(optimized)");
  355. }
  356. if (OptInfo->RemoveUnused && (!(Program.Frozen)))
  357. {
  358. // Remove unreferenced sections.
  359. RemoveUnusedSections (&Program);
  360. #ifdef DEBUGGING_INFO_SUPPORT
  361. if (Program.HaveDebuggingInfo)
  362. {
  363. // Merge all unused sections into a .deleted section.
  364. // Remove the section from early-cutting if we have one.
  365. if (Program.DebuggingInfoSection[0])
  366. Program.DebuggingInfoSection[0]->Handled = FALSE;
  367. Program.DebuggingInfoSection[0] = MergeAllSections (&Program, Program.DebuggingInfoSection[0], TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, 1);
  368. if (Program.DebuggingInfoSection[0])
  369. Program.DebuggingInfoSection[0]->Handled = TRUE;
  370. }
  371. #endif /* DEBUGGING_INFO_SUPPORT */
  372. DoSpecialDump (4, "(cut)");
  373. }
  374. if (!DatVarInfo->Name && OptInfo->MergeConstants && (!(Program.Frozen)))
  375. {
  376. // Merge constants.
  377. MergeConstants (&Program);
  378. DoSpecialDump (4, "(const-merged)");
  379. }
  380. if (OptInfo->ReorderSections && (!(Program.Frozen)))
  381. {
  382. // Reorder sections.
  383. ReorderSections (&Program);
  384. DoSpecialDump (4, "(reordered)");
  385. }
  386. #ifdef FLASH_OS_SUPPORT
  387. if (Program.Type == PT_FLASH_OS)
  388. {
  389. // Flash OS export: merge startup and normal sections separately.
  390. // The resulting two parts are merged later, padding the first
  391. // part to the full 24 KB of the OS startup area (base 1)
  392. // + the 8 KB corresponding to the read protected FlashROM
  393. // area.
  394. // Thus, the startup sections end up in the OS startup area
  395. // (base 1) and the non-startup areas end up in the OS main
  396. // area (base 2), the big OS code part.
  397. // Merge all startup sections.
  398. MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, DI_NONE);
  399. // Merge all normal sections.
  400. MergeAllSections (&Program, NULL, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, DI_NONE);
  401. }
  402. #endif /* FLASH_OS_SUPPORT */
  403. // Merge all initialized sections.
  404. Program.MainSection = MergeAllSections (&Program, NULL, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, DI_NONE);
  405. // Merge all unhandled sections.
  406. Program.MainSection = MergeAllSections (&Program, Program.MainSection, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, DI_NONE);
  407. // Record the size of the BSS section.
  408. if (Program.BSSSection)
  409. OptInfo->BSSSize = Program.BSSSection->Size;
  410. if (Program.MainSection && Program.Library && (Program.MainSection->StartupNumber > 0))
  411. Warning (Program.MainSection->FileName, "Library only contains program startup sections.");
  412. DoDump (5);
  413. // Fix the code (if that is still possible).
  414. FixCode (&Program);
  415. DoDump (6);
  416. // Resolve the relocs pointing to built-in symbols.
  417. Program.ResolveAllBuiltins = TRUE;
  418. // Resolve requested automatic insertions.
  419. if (ResolveRelocs (&Program, TRUE))
  420. {
  421. DoDump (7);
  422. // Do one more optimization pass for relocs to automatic insertions.
  423. FixCode (&Program);
  424. // Remove relocs where possible.
  425. if (FixupRelativeRelocs (&Program))
  426. {
  427. DoDump (8);
  428. if (Program.Calcs)
  429. {
  430. // Export the program to the appropriate files.
  431. if (ExportProgram (&Program, GetOutputFile, FinalizeOutputFile))
  432. {
  433. Result = RESULT_OK;
  434. #ifndef TARGET_EMBEDDED
  435. #ifdef ENABLE_STATS
  436. #include "main_vbs.inc"
  437. #endif /* ENABLE_STATS */
  438. #endif /* !TARGET_EMBEDDED */
  439. }
  440. else
  441. Result = RESULT_EXPORT_ERROR;
  442. }
  443. else
  444. Error (NULL, "No target calculators specified.");
  445. }
  446. }
  447. }
  448. }
  449. }
  450. Cleanup: ATTRIBUTE_UNUSED
  451. // Final Cleanup.
  452. FreeProgram (&Program);
  453. return Result;
  454. }