main.c 17 KB

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