special.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416
  1. /* special.c: Routines to handle special characteristics of the linker
  2. Copyright (C) 2002-2004 Sebastian Reichelt
  3. Copyright (C) 2003-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 "special.h"
  18. #include "integers.h"
  19. #include "manip.h"
  20. #include "insert/insert.h"
  21. #include <string.h>
  22. #include <stdlib.h>
  23. // Try to translate an external symbol into a special-feature symbol used by the linker.
  24. // If the symbol contains a number, it is written to the variable pointed to by Number.
  25. SpecialExternalSymbolTypes TranslateSpecialExternalSymbol (PROGRAM *Program, char *SymbolName, void **Reference, OFFSET *Number)
  26. {
  27. SpecialExternalSymbolTypes SymType = ST_NORMAL;
  28. char *SymNum = SymbolName, *Divider = NULL;
  29. int NumBase = 16;
  30. if (!(strncmp (SymbolName, "tiamsapi_", sizeof ("tiamsapi_") - 1)))
  31. {
  32. SymType = ST_ROM_CALL;
  33. SymNum += sizeof ("tiamsapi_") - 1;
  34. NumBase = 10;
  35. }
  36. if (!(strncmp (SymbolName, "_ROM_CALL_", sizeof ("_ROM_CALL_") - 1)))
  37. {
  38. SymType = ST_ROM_CALL;
  39. SymNum += sizeof ("_ROM_CALL_") - 1;
  40. }
  41. else if (!(strncmp (SymbolName, "_RAM_CALL_", sizeof ("_RAM_CALL_") - 1)))
  42. {
  43. SymType = ST_RAM_CALL;
  44. SymNum += sizeof ("_RAM_CALL_") - 1;
  45. }
  46. else if (!(strncmp (SymbolName, "_extraramaddr@", sizeof ("_extraramaddr@") - 1)))
  47. {
  48. SymType = ST_EXTRA_RAM;
  49. SymNum += sizeof ("_extraramaddr@") - 1;
  50. }
  51. else if (!(strncmp (SymbolName, "_extraramaddr__", sizeof ("_extraramaddr__") - 1)))
  52. {
  53. SymType = ST_EXTRA_RAM;
  54. SymNum += sizeof ("_extraramaddr__") - 1;
  55. }
  56. else if (((Divider = strchr (SymbolName, '@'))) || (((Divider = strstr (SymbolName, "__"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
  57. {
  58. if (*Divider == '@')
  59. SymNum = Divider + 1;
  60. else
  61. SymNum = Divider + 2;
  62. if (strlen (SymNum) == 4)
  63. SymType = ST_LIB_CALL;
  64. }
  65. if (SymType != ST_NORMAL)
  66. {
  67. // Get the number the symbol contains (in hex).
  68. if (Number)
  69. {
  70. char *Err;
  71. *Number = strtoul (SymNum, &Err, NumBase);
  72. // If the number has an error in it, revert to normal symbol.
  73. if (*Err)
  74. SymType = ST_NORMAL;
  75. }
  76. }
  77. if (SymType == ST_LIB_CALL)
  78. {
  79. // Cut SymbolName at the divider.
  80. *Divider = 0;
  81. // Get a reference to the library identified by SymbolName.
  82. if (Reference)
  83. {
  84. *Reference = GetLibrary (Program, SymbolName);
  85. if (!(*Reference))
  86. SymType = ST_NORMAL;
  87. }
  88. }
  89. return SymType;
  90. }
  91. // Handle the symbol if it is a special one.
  92. // Returns TRUE if it was special; in this case it should not be used.
  93. BOOLEAN HandleSpecialSymbol (PROGRAM *Program, const char *SymbolName)
  94. {
  95. BOOLEAN SymbolNameMatches (const char *Name)
  96. {
  97. return (!(strcmp (SymbolName, Name)));
  98. }
  99. const char *Divider;
  100. // All special symbols start with an underscore.
  101. if (SymbolName [0] == '_')
  102. {
  103. SymbolName++;
  104. // The most important special symbol: __ref_all_xxx.
  105. // It adds xxx to the global imports.
  106. if (!(strncmp (SymbolName, "_ref_all_", sizeof ("_ref_all_") - 1)))
  107. {
  108. if (!(Program->IgnoreGlobalImports))
  109. AddGlobalImport (Program, SymbolName + sizeof ("_ref_all_") - 1);
  110. }
  111. else if (SymbolNameMatches ("tigcc_native"))
  112. {
  113. // Kernel is the default type. Everything else must be defined explicitly
  114. // and should therefore take precedence over _tigcc_native.
  115. if (Program->Type == PT_KERNEL)
  116. Program->Type = PT_NATIVE;
  117. }
  118. else if (SymbolNameMatches ("nostub"))
  119. {
  120. SECTION *FirstSection = GetFirst (Program->Sections);
  121. if (FirstSection && (!(FirstSection->StartupNumber)))
  122. FirstSection->Essential = TRUE;
  123. Program->Type = PT_NOSTUB;
  124. }
  125. #ifdef NOSTUB_DLL_SUPPORT
  126. else if (SymbolNameMatches ("nostub_dll"))
  127. {
  128. SECTION *FirstSection = GetFirst (Program->Sections);
  129. if (FirstSection && (!(FirstSection->StartupNumber)))
  130. FirstSection->Essential = TRUE;
  131. Program->Type = PT_NOSTUB_DLL;
  132. Program->Library = TRUE;
  133. }
  134. #endif /* NOSTUB_DLL_SUPPORT */
  135. #ifdef FARGO_SUPPORT
  136. else if (SymbolNameMatches ("fargo"))
  137. Program->Type = PT_FARGO;
  138. #endif /* FARGO_SUPPORT */
  139. #ifdef FLASH_OS_SUPPORT
  140. else if (SymbolNameMatches ("flash_os"))
  141. Program->Type = PT_FLASH_OS;
  142. #endif /* FLASH_OS_SUPPORT */
  143. else if (SymbolNameMatches ("library"))
  144. {
  145. Program->Library = TRUE;
  146. #ifdef FARGO_SUPPORT
  147. // Under Fargo, _library is a normal symbol as well.
  148. if (Program->Type == PT_FARGO)
  149. return FALSE;
  150. #endif /* FARGO_SUPPORT */
  151. }
  152. else if (SymbolNameMatches ("ti92"))
  153. {
  154. Program->Calcs |= CALC_TI92;
  155. }
  156. else if (SymbolNameMatches ("ti89"))
  157. {
  158. Program->Calcs |= CALC_TI89;
  159. Program->KernelFlags |= 0x02;
  160. }
  161. else if (SymbolNameMatches ("ti89ti"))
  162. {
  163. Program->Calcs |= CALC_TI89 | CALC_FLAG_TITANIUM;
  164. Program->KernelFlags |= 0x42;
  165. }
  166. else if (SymbolNameMatches ("ti92plus"))
  167. {
  168. Program->Calcs |= CALC_TI92PLUS;
  169. Program->KernelFlags |= 0x01;
  170. }
  171. else if (SymbolNameMatches ("v200"))
  172. {
  173. Program->Calcs |= CALC_V200;
  174. Program->KernelFlags |= 0x20;
  175. }
  176. else if (!(strncmp (SymbolName, "flag_", sizeof ("flag_") - 1)))
  177. Program->KernelFlags |= (1 << strtoul (SymbolName + sizeof ("flag_") - 1, NULL, 10));
  178. else if (!(strncmp (SymbolName, "version", sizeof ("version") - 1)))
  179. Program->Version = strtoul (SymbolName + sizeof ("version") - 1, NULL, 16);
  180. else if (!(strcmp (SymbolName, "_ld_use_fline_jumps")))
  181. {
  182. if (Program->OptimizeInfo)
  183. Program->OptimizeInfo->UseFLineJumps = TRUE;
  184. }
  185. else if (!(strcmp (SymbolName, "_ld_use_4byte_fline_jumps")))
  186. {
  187. if (Program->OptimizeInfo)
  188. Program->OptimizeInfo->Use4ByteFLineJumps = TRUE;
  189. }
  190. else if (!(strcmp (SymbolName, SYM_IGNORE_GLOBAL_IMPORTS + 1)))
  191. Program->IgnoreGlobalImports = TRUE;
  192. else if (SymbolNameMatches (SYM_OMIT_BSS_INIT + 1) || SymbolNameMatches (SYM_ALL_RELOCS + 1))
  193. // These are mostly file-local special symbols; they are handled
  194. // by the importing function.
  195. ;
  196. else
  197. // Not a special symbol.
  198. return FALSE;
  199. // The symbol was handled here.
  200. return TRUE;
  201. }
  202. else if (((Divider = strstr (SymbolName, "@version"))) || (((Divider = strstr (SymbolName, "__version"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
  203. {
  204. // Required minimum version number for a library.
  205. const char *Version;
  206. VERSION VersionNumber;
  207. if (*Divider == '@')
  208. Version = Divider + sizeof ("@version") - 1;
  209. else
  210. Version = Divider + sizeof ("__version") - 1;
  211. VersionNumber = strtoul (Version, NULL, 16);
  212. if (VersionNumber)
  213. {
  214. if (Divider - SymbolName <= MAX_SYM_LEN)
  215. {
  216. char LibName[MAX_SYM_LEN+1];
  217. LIBRARY *Library;
  218. strncpy (LibName, SymbolName, Divider - SymbolName);
  219. LibName [Divider - SymbolName] = 0;
  220. Library = GetLibrary (Program, LibName);
  221. if (Library && (Library->Version < VersionNumber))
  222. Library->Version = VersionNumber;
  223. }
  224. return TRUE;
  225. }
  226. }
  227. return FALSE;
  228. }
  229. // Translate a section name into a startup section number.
  230. // Returns 0 if the name does not represent a startup section.
  231. OFFSET GetStartupSectionNumber (const char *SectionName, SIZE MaxLen)
  232. {
  233. // Check if it looks like a startup section.
  234. if ((MaxLen > (SIZE) (sizeof ("_st") - 1)) && (!(strncmp (SectionName, "_st", sizeof ("_st") - 1))))
  235. {
  236. // Copy the section name to a temporary null-terminated location.
  237. char SecName[MaxLen+1];
  238. memset (SecName, 0, MaxLen + 1);
  239. strncpy (SecName, SectionName, MaxLen);
  240. // Check whether it is a library startup section.
  241. if (SecName [sizeof ("_st") - 1] == 'l')
  242. {
  243. // Library startup sections are special:
  244. // They may always be included, even if the file is not executable.
  245. // Therefore they get a negative number to distinguish them.
  246. OFFSET RealNum = strtoul (SecName + sizeof ("_stl") - 1, NULL, 10);
  247. return (RealNum ? RealNum - 10000 : 0);
  248. }
  249. else
  250. return (strtoul (SecName + sizeof ("_st") - 1, NULL, 10));
  251. }
  252. else
  253. return 0;
  254. }
  255. // Translate a symbol name into the number of an exported function, if the
  256. // function is meant to be exported.
  257. // Returns -1 if it is not an exported function.
  258. OFFSET GetExportNumber (const char *SymbolName)
  259. {
  260. const char *Divider;
  261. if (((Divider = strchr (SymbolName, '@'))) || (((Divider = strstr (SymbolName, "__"))) && (SymbolName [0] != '_') && (SymbolName [0] != '.') && (strncmp (SymbolName, "L_", sizeof ("L_") - 1))))
  262. {
  263. OFFSET Number;
  264. char *Err;
  265. if (*Divider == '@')
  266. Divider++;
  267. else
  268. Divider += 2;
  269. Number = strtoul (Divider, &Err, 16);
  270. if (*Err)
  271. return (-1);
  272. return Number;
  273. }
  274. else
  275. return (-1);
  276. }
  277. // Add all imports with names defined by this program, if they are needed.
  278. BOOLEAN CreateSpecialGlobalImports (PROGRAM *Program)
  279. {
  280. BOOLEAN Result = TRUE;
  281. SECTION *TempSection;
  282. if (Program->Type == PT_KERNEL)
  283. {
  284. if (Program->Library)
  285. Result = Result && AddGlobalImport (Program, "__kernel_library_header");
  286. else
  287. Result = Result && AddGlobalImport (Program, "__kernel_program_header");
  288. }
  289. #ifdef FARGO_SUPPORT
  290. else if (Program->Type == PT_FARGO)
  291. {
  292. if (Program->Library)
  293. Result = Result && AddGlobalImport (Program, "__fargo_library_header");
  294. else
  295. Result = Result && AddGlobalImport (Program, "__fargo_program_header");
  296. }
  297. #endif /* FARGO_SUPPORT */
  298. #ifdef FLASH_OS_SUPPORT
  299. else if (Program->Type == PT_FLASH_OS)
  300. Result = Result && AddGlobalImport (Program, "__flash_os_header");
  301. #endif /* FLASH_OS_SUPPORT */
  302. if (Program->Constructors.Start)
  303. Result = Result && AddGlobalImport (Program, "__handle_constructors");
  304. if (Program->Destructors.Start)
  305. Result = Result && AddGlobalImport (Program, "__handle_destructors");
  306. if (Program->BSSSection && Program->BSSSection->Initialized)
  307. Result = Result && AddGlobalImport (Program, "__initialize_bss");
  308. // Handle BSS section if any.
  309. if (Program->BSSSection && (!(Program->BSSSection->Handled)))
  310. {
  311. GLOBAL_IMPORT *Import = CreateGlobalImport (Program, "__handle_bss");
  312. if (Import)
  313. {
  314. // This is the import that will mark the BSS section as handled
  315. // if it succeeds.
  316. Program->BSSImport = Import;
  317. // Try to resolve it against available archives.
  318. ResolveGlobalImport (Program, Import);
  319. // The BSS section is simply merged into the rest if it is not
  320. // handled.
  321. Import->Succeeded = TRUE;
  322. }
  323. else
  324. Result = FALSE;
  325. }
  326. // Handle absolute relocs if there are any.
  327. for_each (TempSection, Program->Sections)
  328. {
  329. BOOLEAN Done = FALSE;
  330. RELOC *TempReloc;
  331. for_each (TempReloc, TempSection->Relocs)
  332. {
  333. if ((!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled)))))
  334. {
  335. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_relocs");
  336. if (Import)
  337. // Relocs are either handled by the export format, or a
  338. // warning is emitted.
  339. Import->Succeeded = TRUE;
  340. else
  341. Result = FALSE;
  342. Done = TRUE;
  343. break;
  344. }
  345. }
  346. if (Done)
  347. break;
  348. }
  349. // Handle ROM calls if there are any.
  350. for_each (TempSection, Program->Sections)
  351. {
  352. if (!(IsEmpty (TempSection->ROMCalls)))
  353. {
  354. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_rom_calls");
  355. if (Import)
  356. // ROM calls are either handled by the export format, or a
  357. // warning is emitted.
  358. Import->Succeeded = TRUE;
  359. else
  360. Result = FALSE;
  361. break;
  362. }
  363. }
  364. // Handle RAM calls if there are any.
  365. for_each (TempSection, Program->Sections)
  366. {
  367. if (!(IsEmpty (TempSection->RAMCalls)))
  368. {
  369. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_ram_calls");
  370. if (Import)
  371. // RAM calls are either handled by the export format, or a
  372. // warning is emitted.
  373. Import->Succeeded = TRUE;
  374. else
  375. Result = FALSE;
  376. break;
  377. }
  378. }
  379. // Handle libraries if any libraries are referenced.
  380. if (!(IsEmpty (Program->Libraries)))
  381. {
  382. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_libraries");
  383. if (Import)
  384. // Libraries are either handled by the export format, or a
  385. // warning is emitted.
  386. Import->Succeeded = TRUE;
  387. else
  388. Result = FALSE;
  389. }
  390. // Handle _nostub comments if any.
  391. if ((Program->Type == PT_NATIVE) || (Program->Type == PT_NOSTUB))
  392. {
  393. BOOLEAN NostubComments = FALSE;
  394. for_each (TempSection, Program->Sections)
  395. {
  396. SYMBOL *TempSymbol;
  397. for_each (TempSymbol, TempSection->Symbols)
  398. {
  399. if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, "_nostub_data__", sizeof ("_nostub_data__") - 1))))
  400. {
  401. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + sizeof ("_nostub_") - 1);
  402. if (ExportNumber >= 0)
  403. {
  404. NostubComments = TRUE;
  405. TempSection->Essential = TRUE;
  406. break;
  407. }
  408. }
  409. }
  410. }
  411. if (NostubComments)
  412. Result = Result && AddGlobalImport (Program, "__nostub_comment_header");
  413. }
  414. #ifdef DATA_VAR_SUPPORT
  415. // Handle data variable if desired.
  416. if (Program->DataVarInfo->Name && Program->DataSection)
  417. {
  418. Result = Result && (AddGlobalImport (Program, "__handle_data_var"));
  419. if (Program->DataVarInfo->CreateCopy)
  420. {
  421. Result = Result && (AddGlobalImport (Program, "__data_var_create_copy"));
  422. if (Program->DataVarInfo->CopyOnlyIfArchived)
  423. Result = Result && (AddGlobalImport (Program, "__data_var_copy_if_archived"));
  424. }
  425. }
  426. #endif /* DATA_VAR_SUPPORT */
  427. return Result;
  428. }
  429. // If the reloc or its relation point to a special ld-exported symbol,
  430. // change it to the appropriate value if possible. FALSE is returned
  431. // only if it is not a special symbol location, or if there was an error.
  432. BOOLEAN ResolveSpecialSymbolReloc (RELOC *Reloc, BOOLEAN *TryAgain)
  433. {
  434. // At first, resolve the relation, because if this is a built-in
  435. // number, we cannot write it into the section contents directly,
  436. // but we have to subtract it from FixedOffset.
  437. BOOLEAN Result = ResolveSpecialSymbolRelocRelation (Reloc, TryAgain);
  438. // Now resolve the target.
  439. return (ResolveSpecialSymbolRelocTarget (Reloc, TryAgain) ? Result : FALSE);
  440. }
  441. // If the reloc points to a special ld-exported symbol, change it to the
  442. // appropriate value if possible. FALSE is returned only if it is not a
  443. // special symbol reloc, or if there was an error.
  444. BOOLEAN ResolveSpecialSymbolRelocTarget (RELOC *Reloc, BOOLEAN *TryAgain)
  445. {
  446. BOOLEAN Result = FALSE;
  447. SECTION *Section = Reloc->Parent;
  448. LOCATION *Location = &(Reloc->Target);
  449. // If the relation is an unresolved reference to a builtin number,
  450. // do not even try to resolve the target. This would only cause
  451. // trouble, since we would need to handle it immediately if it
  452. // resolved to a number. There will be another call to this anyway
  453. // after the relation has finally been resolved.
  454. // Usually, we would at least need to set the Target.Builtin flag.
  455. // However, currently all tests which check for Target.Builtin also
  456. // check for Relation or Relative in general. If this ever changes,
  457. // this code will break.
  458. if (Reloc->Relation && Reloc->Relation->Builtin)
  459. return TRUE;
  460. if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
  461. {
  462. // If it has resolved to a number, write it into the section
  463. // contents.
  464. if (!(Location->Symbol || Location->SymbolName))
  465. {
  466. if (Reloc->Relation)
  467. Warning (GetFileName (Section, Reloc->Location), "Ignoring invalid negative reference to `%s' at 0x%lX.", Reloc->Relation->SymbolName, (long) Reloc->Location);
  468. if ((Reloc->Location >= 0) && (Reloc->Location + Reloc->Size <= Section->Size))
  469. {
  470. // Add the target offset (to support things such as "__ld_xxx+1").
  471. OFFSET NewValue = Location->Offset + Reloc->FixedOffset;
  472. if (Reloc->Relative)
  473. Warning (GetFileName (Section, Reloc->Location), "Invalid relative reference to built-in number `%s' at 0x%lX; changing to absolute.", Reloc->Target.SymbolName, (long) Reloc->Location);
  474. // Check if the section contents at the reloc are zero.
  475. if (!(IsZeroDataRange (Section, Reloc->Location, Reloc->Location + Reloc->Size)))
  476. Warning (GetFileName (Section, Reloc->Location), "Builtin reloc at 0x%lX to `%s' on nonzero section contents. Overlapping with another?", (long) Reloc->Location, Reloc->Target.SymbolName);
  477. // Resolve the reloc by writing the value into the section.
  478. Result = AddTI (Section->Data + Reloc->Location, Reloc->Size, NewValue, TRUE, TRUE);
  479. if (!Result)
  480. Error (GetFileName (Section, Reloc->Location), "Number `%s' (=%ld) too large for size %ld reloc at 0x%lX.", Reloc->Target.SymbolName, (long) NewValue, (long) Reloc->Size, (long) Reloc->Location);
  481. }
  482. else
  483. {
  484. Warning (GetFileName (Section, Reloc->Location), "Removing reloc at 0x%lX to `%s' outside of section.", (long) Reloc->Location, Reloc->Target.SymbolName);
  485. Result = TRUE;
  486. }
  487. FreeReloc (Reloc);
  488. }
  489. else
  490. Result = TRUE;
  491. }
  492. return Result;
  493. }
  494. // If the reloc's relation points to a special ld-exported symbol,
  495. // change it to the appropriate value if possible. FALSE is returned
  496. // only if it is not a special symbol location, or if there was an error.
  497. BOOLEAN ResolveSpecialSymbolRelocRelation (RELOC *Reloc, BOOLEAN *TryAgain)
  498. {
  499. BOOLEAN Result = FALSE;
  500. SECTION *Section = Reloc->Parent;
  501. LOCATION *Location = Reloc->Relation;
  502. if (Reloc->Relation)
  503. {
  504. // Try to resolve the relation.
  505. if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
  506. {
  507. // Check if it has really been resolved.
  508. BOOLEAN Resolved = (Location->Symbol != NULL);
  509. // If it has been resolved to a number, subtract it from
  510. // FixedOffset.
  511. if (!(Location->Symbol || Location->SymbolName))
  512. {
  513. Reloc->FixedOffset -= Location->Offset;
  514. FreeRelocRelation (Reloc);
  515. Resolved = TRUE;
  516. }
  517. Result = TRUE;
  518. }
  519. }
  520. return Result;
  521. }
  522. // If the location points to a special ld-exported symbol, change it to the
  523. // appropriate value if possible. FALSE is returned only if it is not a
  524. // special symbol location, or if there was an error.
  525. // Warning: If the special symbol resolves to a number, Location->Symbol and
  526. // Location->SymbolName will both be NULL, and Location->Offset will contain
  527. // the number.
  528. BOOLEAN ResolveSpecialSymbolLocation (SECTION *Section, LOCATION *Location, BOOLEAN *TryAgain)
  529. {
  530. const char *SymName = Location->SymbolName;
  531. BOOLEAN SymNameMatches (const char *Name)
  532. {
  533. return (!(strcmp (SymName, Name)));
  534. }
  535. // Locations that are already resolved do not need any treatment.
  536. if (Location->Symbol)
  537. return FALSE;
  538. // All special symbols start with '_'.
  539. if (SymName && (SymName [0] == '_'))
  540. {
  541. PROGRAM *Program = Section->Parent;
  542. BOOLEAN SetToEntryPoint = FALSE;
  543. OFFSET NewValue = 0;
  544. SymName++;
  545. // All built-in symbols start with "__ld_".
  546. if (!(strncmp (SymName, SYMPF_BUILTIN + 1, sizeof (SYMPF_BUILTIN) - 2)))
  547. {
  548. SIZE SymNameLength;
  549. BOOLEAN HasValue = FALSE;
  550. SYMBOL *NewSymbol = NULL;
  551. OFFSET NewTargetOffset = 0;
  552. SECTION *TempSection;
  553. // Skip the "__ld_" prefix.
  554. SymName += sizeof (SYMPF_BUILTIN) - 2;
  555. SymNameLength = strlen (SymName);
  556. // Find (but do not resolve) calculator constants.
  557. if (IsCalcBuiltinLocation (Location))
  558. ;
  559. // Resolve references to insertions.
  560. else if (!(strncmp (SymName, SYMPF_INSERT, sizeof (SYMPF_INSERT) - 1)))
  561. {
  562. if ((!(TempSection = Program->MainSection))
  563. || (!(NewSymbol = HandleAutoInsertion (TempSection, Location->SymbolName))))
  564. return TRUE;
  565. }
  566. // Resolve "has_...s".
  567. else if ((!(strncmp (SymName, "has_", sizeof ("has_") - 1))) && (SymName [SymNameLength - 1] == 's'))
  568. {
  569. if (Program->ResolveAllBuiltins)
  570. {
  571. Program->Frozen = TRUE;
  572. if (GetBuiltinValue (Program, SymName + (sizeof ("has_") - 1), SymNameLength - 1 - (sizeof ("has_") - 1), &NewValue, -1))
  573. HasValue = TRUE;
  574. }
  575. }
  576. // Resolve "..._count".
  577. else if ((SymNameLength > ((SIZE) (sizeof ("_count") - 1))) && (!(strcmp (SymName + SymNameLength - (sizeof ("_count") - 1), "_count"))))
  578. {
  579. if (Program->ResolveAllBuiltins)
  580. {
  581. Program->Frozen = TRUE;
  582. if (GetBuiltinValue (Program, SymName, SymNameLength - (sizeof ("_count") - 1), &NewValue, 0))
  583. HasValue = TRUE;
  584. }
  585. }
  586. else if (SymNameMatches ("entry_point"))
  587. SetToEntryPoint = TRUE;
  588. else if (SymNameMatches ("entry_point_plus_0x8000"))
  589. {
  590. SetToEntryPoint = TRUE;
  591. NewValue = 0x8000;
  592. }
  593. else if (SymNameMatches ("constructors_start"))
  594. {
  595. if (!(NewSymbol = Program->Constructors.Start))
  596. return TRUE;
  597. }
  598. else if (SymNameMatches ("constructors_end"))
  599. {
  600. if (!(NewSymbol = Program->Constructors.End))
  601. return TRUE;
  602. }
  603. else if (SymNameMatches ("constructors_size"))
  604. {
  605. if (Program->Constructors.Start && Program->Constructors.End)
  606. {
  607. NewValue = Program->Constructors.End->Location - Program->Constructors.Start->Location;
  608. HasValue = TRUE;
  609. }
  610. else if (Program->ResolveAllBuiltins)
  611. HasValue = TRUE;
  612. }
  613. else if (SymNameMatches ("destructors_start"))
  614. {
  615. if (!(NewSymbol = Program->Destructors.Start))
  616. return TRUE;
  617. }
  618. else if (SymNameMatches ("destructors_end"))
  619. {
  620. if (!(NewSymbol = Program->Destructors.End))
  621. return TRUE;
  622. }
  623. else if (SymNameMatches ("destructors_size"))
  624. {
  625. if (Program->Destructors.Start && Program->Destructors.End)
  626. {
  627. NewValue = Program->Destructors.End->Location - Program->Destructors.Start->Location;
  628. HasValue = TRUE;
  629. }
  630. else if (Program->ResolveAllBuiltins)
  631. HasValue = TRUE;
  632. }
  633. else if (SymNameMatches ("data_start"))
  634. {
  635. if (Program->DataSection)
  636. NewSymbol = Program->DataSection->SectionSymbol;
  637. else
  638. return TRUE;
  639. }
  640. else if (SymNameMatches ("data_end"))
  641. {
  642. if (Program->DataSection)
  643. {
  644. NewSymbol = Program->DataSection->SectionSymbol;
  645. NewTargetOffset = Program->DataSection->Size;
  646. }
  647. else
  648. return TRUE;
  649. }
  650. else if (SymNameMatches ("data_size"))
  651. {
  652. if (Program->DataSection)
  653. {
  654. NewValue = Program->DataSection->Size;
  655. HasValue = TRUE;
  656. }
  657. else if (Program->ResolveAllBuiltins)
  658. HasValue = TRUE;
  659. }
  660. else if (SymNameMatches ("bss_start"))
  661. {
  662. if (Program->BSSSection)
  663. NewSymbol = Program->BSSSection->SectionSymbol;
  664. else
  665. return TRUE;
  666. }
  667. else if (SymNameMatches ("bss_end"))
  668. {
  669. if (Program->BSSSection)
  670. {
  671. NewSymbol = Program->BSSSection->SectionSymbol;
  672. NewTargetOffset = Program->BSSSection->Size;
  673. }
  674. else
  675. return TRUE;
  676. }
  677. else if (SymNameMatches ("bss_size"))
  678. {
  679. if (Program->BSSSection)
  680. {
  681. NewValue = Program->BSSSection->Size;
  682. HasValue = TRUE;
  683. }
  684. else if (Program->ResolveAllBuiltins)
  685. HasValue = TRUE;
  686. }
  687. else if (SymNameMatches ("file_version"))
  688. {
  689. if (Program->ResolveAllBuiltins || Program->Version)
  690. {
  691. NewValue = Program->Version;
  692. HasValue = TRUE;
  693. }
  694. }
  695. else if (SymNameMatches ("link_time_year"))
  696. {
  697. if (Program->ResolveAllBuiltins)
  698. {
  699. NewValue = Program->LinkTime.Year;
  700. HasValue = TRUE;
  701. }
  702. }
  703. else if (SymNameMatches ("link_time_month"))
  704. {
  705. if (Program->ResolveAllBuiltins)
  706. {
  707. NewValue = Program->LinkTime.Month;
  708. HasValue = TRUE;
  709. }
  710. }
  711. else if (SymNameMatches ("link_time_day"))
  712. {
  713. if (Program->ResolveAllBuiltins)
  714. {
  715. NewValue = Program->LinkTime.Day;
  716. HasValue = TRUE;
  717. }
  718. }
  719. else if (SymNameMatches ("link_time_timestamp"))
  720. {
  721. if (Program->ResolveAllBuiltins)
  722. {
  723. NewValue = Program->LinkTime.LinkTime;
  724. HasValue = TRUE;
  725. }
  726. }
  727. else if (SymNameMatches ("kernel_flags"))
  728. {
  729. if (Program->ResolveAllBuiltins)
  730. {
  731. NewValue = Program->KernelFlags;
  732. HasValue = TRUE;
  733. }
  734. }
  735. else if (SymNameMatches ("kernel_bss_table"))
  736. {
  737. if (Program->BSSSection)
  738. {
  739. strcpy ((char *) (Location->SymbolName), "__kernel_bss_table");
  740. if (TryAgain)
  741. *TryAgain = TRUE;
  742. // This prevents the section from being merged, and prevents
  743. // relocs to it from being emitted.
  744. Program->BSSSection->Handled = TRUE;
  745. return FALSE;
  746. }
  747. else if (Program->ResolveAllBuiltins)
  748. SetToEntryPoint = TRUE;
  749. }
  750. else if (SymNameMatches ("program_size"))
  751. {
  752. if (Program->ResolveAllBuiltins && Program->MainSection)
  753. {
  754. NewValue = Program->MainSection->Size;
  755. HasValue = TRUE;
  756. }
  757. else
  758. return TRUE;
  759. }
  760. else if (SymNameMatches ("kernel_export_table"))
  761. {
  762. BOOLEAN HasExports = FALSE;
  763. for_each (TempSection, Program->Sections)
  764. {
  765. SYMBOL *TempSymbol;
  766. for_each (TempSymbol, TempSection->Symbols)
  767. {
  768. if (TempSymbol->Exported)
  769. {
  770. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
  771. if (ExportNumber >= 0)
  772. {
  773. HasExports = TRUE;
  774. TempSection->Essential = TRUE;
  775. break;
  776. }
  777. }
  778. }
  779. }
  780. if (HasExports)
  781. {
  782. strcpy ((char *) (Location->SymbolName), "__kernel_export_table");
  783. if (TryAgain)
  784. *TryAgain = TRUE;
  785. return FALSE;
  786. }
  787. else if (Program->ResolveAllBuiltins)
  788. SetToEntryPoint = TRUE;
  789. }
  790. #ifdef DATA_VAR_SUPPORT
  791. else if (SymNameMatches ("data_var_name_end"))
  792. {
  793. // Point the reloc to the terminating zero byte of the name.
  794. if (Program->DataVarInfo->Name)
  795. {
  796. strcpy ((char *) (Location->SymbolName), "__data_var_name_start");
  797. Location->Offset += strlen (Program->DataVarInfo->Name) + 1;
  798. if (TryAgain)
  799. *TryAgain = TRUE;
  800. return FALSE;
  801. }
  802. }
  803. #endif /* DATA_VAR_SUPPORT */
  804. else
  805. return FALSE;
  806. if (!SetToEntryPoint)
  807. {
  808. if (HasValue)
  809. {
  810. // Point the location to the new value.
  811. Location->Symbol = NULL;
  812. FreeLocationSymbolName (Section, Location);
  813. Location->Offset += NewValue;
  814. }
  815. else if (NewSymbol)
  816. {
  817. // Point the location to the new symbol.
  818. Location->Symbol = NewSymbol;
  819. FreeLocationSymbolName (Section, Location);
  820. Location->Offset += NewTargetOffset;
  821. }
  822. else
  823. Location->Builtin = TRUE;
  824. return TRUE;
  825. }
  826. }
  827. // If this is a reloc to a kernel-specific symbol, point it to the
  828. // entry point. The result of this is that the reloc's value
  829. // becomes 0 if the reloc was made up by something like
  830. // _exit-__kernel_entry_point.
  831. else if (SymNameMatches ("exit") || SymNameMatches ("comment") || SymNameMatches ("extraram") || SymNameMatches ("library"))
  832. SetToEntryPoint = TRUE;
  833. if (SetToEntryPoint)
  834. {
  835. if (Program->EntryPoint.Symbol)
  836. {
  837. Location->Symbol = Program->EntryPoint.Symbol;
  838. FreeLocationSymbolName (Section, Location);
  839. Location->Offset += Program->EntryPoint.Offset + NewValue;
  840. }
  841. return TRUE;
  842. }
  843. }
  844. return FALSE;
  845. }
  846. // Count the items for a specific built-in symbol, specified by SymName
  847. // and SymNameLength. If TrueValue is nonzero, items are not counted,
  848. // but NewValue is set to this value if at least one item was found. In
  849. // that case, if Program->ResolveAllBuiltins is false, NewValue may be
  850. // unchanged even though there are some items; you need to check back
  851. // later when Program->ResolveAllBuiltins is true.
  852. BOOLEAN GetBuiltinValue (PROGRAM *Program, const char *SymName, SIZE SymNameLength, OFFSET *NewValue, OFFSET TrueValue)
  853. {
  854. #define Count(n,op,code) \
  855. ({ \
  856. register OFFSET n__ = (n); \
  857. if (TrueValue) \
  858. { \
  859. if (n__) \
  860. { \
  861. *NewValue = TrueValue; \
  862. code; \
  863. } \
  864. } \
  865. else \
  866. *NewValue op n__; \
  867. })
  868. #define SetCounter(n) (Count ((n), =, (void) 0))
  869. #define IncreaseCounter(n) (Count ((n), +=, break))
  870. BOOLEAN SymNameMatches (const char *Name)
  871. {
  872. return (!(strncmp (SymName, Name, SymNameLength)));
  873. }
  874. SECTION *TempSection;
  875. RELOC *TempReloc;
  876. SYMBOL *TempSymbol;
  877. if (SymNameMatches ("constructor"))
  878. {
  879. if (Program->Constructors.Start && Program->Constructors.End)
  880. SetCounter ((Program->Constructors.End->Location - Program->Constructors.Start->Location) >> 2);
  881. }
  882. else if (SymNameMatches ("destructor"))
  883. {
  884. if (Program->Destructors.Start && Program->Destructors.End)
  885. SetCounter ((Program->Destructors.End->Location - Program->Destructors.Start->Location) >> 2);
  886. }
  887. else if (SymNameMatches ("reloc"))
  888. {
  889. // Count all absolute relocs.
  890. // Relative relocs will either be resolved completely or
  891. // produce errors.
  892. for_each (TempSection, Program->Sections)
  893. {
  894. IncreaseCounter (TempSection->Relocs.EmittedCount);
  895. // Since relocs may be removed, if ResolveAllBuiltins
  896. // is false, do not handle TrueValue.
  897. if ((!TrueValue) || Program->ResolveAllBuiltins)
  898. {
  899. for_each (TempReloc, TempSection->Relocs)
  900. if (!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled))))
  901. IncreaseCounter (1);
  902. }
  903. }
  904. }
  905. else if (SymNameMatches ("data_ref"))
  906. {
  907. if (Program->DataSection)
  908. {
  909. // Count all absolute relocs to the data section.
  910. for_each (TempSection, Program->Sections)
  911. for_each (TempReloc, TempSection->Relocs)
  912. if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->DataSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
  913. IncreaseCounter (1);
  914. }
  915. }
  916. else if (SymNameMatches ("bss_ref"))
  917. {
  918. if (Program->BSSSection)
  919. {
  920. // Count all absolute relocs to the BSS section.
  921. for_each (TempSection, Program->Sections)
  922. for_each (TempReloc, TempSection->Relocs)
  923. if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->BSSSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
  924. IncreaseCounter (1);
  925. }
  926. }
  927. else if (SymNameMatches ("rom_call"))
  928. {
  929. for_each (TempSection, Program->Sections)
  930. IncreaseCounter (CountItems (TempSection->ROMCalls, ROM_CALL));
  931. }
  932. else if (SymNameMatches ("ram_call"))
  933. {
  934. for_each (TempSection, Program->Sections)
  935. IncreaseCounter (CountItems (TempSection->RAMCalls, RAM_CALL));
  936. }
  937. else if (SymNameMatches ("lib"))
  938. SetCounter (CountItems (Program->Libraries, LIBRARY));
  939. else if (SymNameMatches ("referenced_lib"))
  940. SetCounter (Program->Libraries.ReferencedCount);
  941. else if (SymNameMatches ("export"))
  942. {
  943. // The number of exports is equal to the highest export number + 1.
  944. for_each (TempSection, Program->Sections)
  945. {
  946. for_each (TempSymbol, TempSection->Symbols)
  947. {
  948. if (TempSymbol->Exported)
  949. {
  950. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
  951. if ((ExportNumber >= 0) && (*NewValue < ExportNumber + 1))
  952. Count (ExportNumber + 1, =, break);
  953. }
  954. }
  955. }
  956. }
  957. else if (SymNameMatches ("nostub_comment"))
  958. {
  959. for_each (TempSection, Program->Sections)
  960. {
  961. for_each (TempSymbol, TempSection->Symbols)
  962. {
  963. if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, SYMPF_NOSTUB_DATA, sizeof (SYMPF_NOSTUB_DATA) - 1))))
  964. {
  965. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + (sizeof (SYMPF_NOSTUB_DATA_START) - 1));
  966. if (ExportNumber >= 0)
  967. IncreaseCounter (1);
  968. }
  969. }
  970. }
  971. }
  972. else
  973. return FALSE;
  974. #undef IncreaseCounter
  975. #undef SetCounter
  976. #undef Count
  977. return TRUE;
  978. }
  979. // If the given symbol name belongs to a calculator-specific builtin
  980. // symbol, return a pointer to the part of it that holds the values.
  981. static const char *GetCalcBuiltinValues (const char *SymName)
  982. {
  983. if (!(strncmp (SymName, SYMPF_BUILTIN_CALC_CONST, sizeof (SYMPF_BUILTIN_CALC_CONST) - 1)))
  984. {
  985. return (SymName + (sizeof (SYMPF_BUILTIN_CALC_CONST) - 1));
  986. }
  987. return NULL;
  988. }
  989. // Check if the given location points to a calculator-specific builtin
  990. // symbol.
  991. BOOLEAN IsCalcBuiltinLocation (const LOCATION *Location)
  992. {
  993. return (Location->SymbolName && (GetCalcBuiltinValues (Location->SymbolName) || (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))));
  994. }
  995. // Return whether the reloc can be resolved to a calculator-specific value.
  996. // ResolveSpecialSymbol or something related must have been called on the
  997. // reloc at least once.
  998. BOOLEAN IsPlainCalcBuiltin (const RELOC *Reloc)
  999. {
  1000. // To improve speed, check whether the target and relation (if it exists)
  1001. // are builtin symbols.
  1002. if (Reloc->Target.Builtin && ((!(Reloc->Relation)) || Reloc->Relation->Builtin))
  1003. {
  1004. // Check the target.
  1005. if (IsCalcBuiltinLocation (&(Reloc->Target)))
  1006. {
  1007. // If there is a relation, check it.
  1008. if (Reloc->Relation)
  1009. return IsCalcBuiltinLocation (Reloc->Relation);
  1010. // Otherwise, the reloc may not be relative, since that would
  1011. // mean that it cannot be resolved to a number.
  1012. else
  1013. return (!(Reloc->Relative));
  1014. }
  1015. }
  1016. return FALSE;
  1017. }
  1018. // If the location can be resolved to a calculator-specific value, get the
  1019. // value for the specified calculator.
  1020. // If IsCalcBuiltinLocation returned a positive result for this reloc, this
  1021. // function will not return a negative result.
  1022. BOOLEAN GetCalcBuiltinLocationValue (const LOCATION *Location, ProgramCalcs DestCalc, IMAX *Value)
  1023. {
  1024. // Basic sanity checks.
  1025. if (Value && Location->SymbolName)
  1026. {
  1027. // Special case: __ld_hardware_id
  1028. if (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))
  1029. {
  1030. switch (DestCalc)
  1031. {
  1032. case CALC_TI89:
  1033. *Value = 3;
  1034. break;
  1035. case CALC_TI89 | CALC_FLAG_TITANIUM:
  1036. *Value = 9;
  1037. break;
  1038. case CALC_TI92PLUS:
  1039. *Value = 1;
  1040. break;
  1041. case CALC_V200:
  1042. *Value = 8;
  1043. break;
  1044. default:
  1045. Warning (NULL, SYM_BUILTIN_HARDWARE_ID " not defined for this calculator.");
  1046. *Value = 0;
  1047. }
  1048. *Value += Location->Offset;
  1049. return TRUE;
  1050. }
  1051. else
  1052. {
  1053. // Get the part of the symbol name that holds the values,
  1054. // separated by '_'.
  1055. const char *Values = GetCalcBuiltinValues (Location->SymbolName);
  1056. if (Values)
  1057. {
  1058. // AND out the calculator flags.
  1059. DestCalc &= ~CALC_FLAG_TITANIUM;
  1060. // While we still have at least one value left...
  1061. while (Values)
  1062. {
  1063. // Get the end of the value string.
  1064. const char *ValueEnd = strchr (Values, '_');
  1065. SIZE ValueSize = ValueEnd ? (SIZE) (ValueEnd - Values) : (SIZE) (strlen (Values));
  1066. // If this is the value that belongs to the current calculator,
  1067. // extract the value and return.
  1068. if (DestCalc == 1)
  1069. {
  1070. char *EndPtr = NULL;
  1071. // Create a copy of the value, with a terminating zero byte.
  1072. char ValueStr[ValueSize+1];
  1073. strncpy (ValueStr, Values, ValueSize);
  1074. ValueStr [ValueSize] = 0;
  1075. // Convert this string into a number and return it.
  1076. *Value = strtoul (ValueStr, &EndPtr, 0);
  1077. if (EndPtr && *EndPtr)
  1078. Warning (NULL, "Invalid number `%s' in `%s'.", ValueStr, Location->SymbolName);
  1079. *Value += Location->Offset;
  1080. return TRUE;
  1081. }
  1082. // Advance to the next value.
  1083. Values = ValueEnd ? ValueEnd + 1 : NULL;
  1084. // Advance to the next calculator.
  1085. DestCalc >>= 1;
  1086. }
  1087. // No more values were found, but the function did not exit yet.
  1088. Warning (NULL, "Calculator constant `%s' contains too few values.", Location->SymbolName);
  1089. *Value = 0;
  1090. // We have to return a positive result anyway because
  1091. // IsCalcBuiltinLocation would as well.
  1092. return TRUE;
  1093. }
  1094. }
  1095. }
  1096. return FALSE;
  1097. }
  1098. // If the reloc can be resolved to a calculator-specific value, get the
  1099. // value for the specified calculator.
  1100. // The return value is the same as for IsPlainCalcBuiltin.
  1101. BOOLEAN GetCalcBuiltinValue (const RELOC *Reloc, ProgramCalcs DestCalc, IMAX *Value)
  1102. {
  1103. if (Value)
  1104. {
  1105. // Get the value for the target.
  1106. if (GetCalcBuiltinLocationValue (&(Reloc->Target), DestCalc, Value))
  1107. {
  1108. // If there is a relation, subtract its value.
  1109. if (Reloc->Relation)
  1110. {
  1111. IMAX RelationValue;
  1112. if (!(GetCalcBuiltinLocationValue (Reloc->Relation, DestCalc, &RelationValue)))
  1113. return FALSE;
  1114. *Value -= RelationValue;
  1115. }
  1116. // Otherwise, the reloc may not be relative
  1117. // (see IsPlainCalcBuiltin).
  1118. else if (Reloc->Relative)
  1119. return FALSE;
  1120. *Value += Reloc->FixedOffset;
  1121. return TRUE;
  1122. }
  1123. }
  1124. return FALSE;
  1125. }
  1126. // If required by some special symbol(s) at the end of the section,
  1127. // modify the contents of the section.
  1128. // This can be used to insert special items such as relocation entries.
  1129. // MergedSection specifies the (usually large) part of the program that
  1130. // has already been merged.
  1131. // If necessary, MergedSection is frozen automatically.
  1132. BOOLEAN HandleSectionContents (SECTION *Section, SECTION *MergedSection)
  1133. {
  1134. SYMBOL *Symbol;
  1135. // Search the labels at the end of the secion to find special ones.
  1136. for (Symbol = FindSymbolAtPos (Section, Section->Size, TRUE); Symbol; Symbol = GetNext (Symbol))
  1137. {
  1138. if (!(strncmp (Symbol->Name, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
  1139. return (HandleInsertion (Section, Symbol->Location, Symbol->Name + sizeof (SYMPF_BUILTIN_INSERT) - 1, MergedSection, FALSE));
  1140. }
  1141. return TRUE;
  1142. }
  1143. // Insert contents for an insertion specified by SymbolName, and return
  1144. // a symbol from where the insertion took place.
  1145. // If necessary, Section is frozen automatically.
  1146. SYMBOL *HandleAutoInsertion (SECTION *Section, const char *SymbolName)
  1147. {
  1148. if (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
  1149. {
  1150. CreateSectionSegment (Section);
  1151. // All insertions except compressed ones should be aligned on a 2-byte boundary.
  1152. if ((!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_COMPRESSED, sizeof (SYMPF_BUILTIN_INSERT_COMPRESSED) - 1)))
  1153. || (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_MLINK, sizeof (SYMPF_BUILTIN_INSERT_MLINK) - 1)))
  1154. || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "fargo021_relocs")))
  1155. || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "preos_compressed_tables")))
  1156. || PadSection (Section, 2))
  1157. {
  1158. // Create a new symbol at the end of the section.
  1159. SYMBOL *Result = calloc (1, sizeof (SYMBOL));
  1160. if (Result)
  1161. {
  1162. Result->Parent = Section;
  1163. Result->Location = Section->Size;
  1164. strncpy (Result->Name, SymbolName, MAX_SYM_LEN);
  1165. Result->Exported = TRUE;
  1166. Append (Section->Symbols, Result);
  1167. // Insert the data.
  1168. if (AppendInsertionData (Section, SymbolName + sizeof (SYMPF_BUILTIN_INSERT) - 1, Section, TRUE))
  1169. return Result;
  1170. }
  1171. else
  1172. Error (NULL, "Out of memory.");
  1173. }
  1174. }
  1175. return NULL;
  1176. }
  1177. // Handle an insertion by cutting the section off at the specified location
  1178. // and inserting the contents specified by the name, taking into account
  1179. // that MergedSection specifies the (usually large) part of the program
  1180. // that has already been merged.
  1181. BOOLEAN HandleInsertion (SECTION *Section, OFFSET Location, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
  1182. {
  1183. if (Location == Section->Size)
  1184. return AppendInsertionData (Section, Name, MergedSection, AlwaysTerminate);
  1185. else
  1186. return TRUE;
  1187. }
  1188. // Append the data required by an insertion (specified by name) to the
  1189. // section specified by Section, taking into account that MergedSection
  1190. // specifies the (usually large) part of the program that has already
  1191. // been merged.
  1192. BOOLEAN AppendInsertionData (SECTION *Section, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
  1193. {
  1194. BOOLEAN NameMatches (const char *InsertionName)
  1195. {
  1196. return (!(strcmp (Name, InsertionName)));
  1197. }
  1198. PROGRAM *Program = Section->Parent;
  1199. #ifdef DATA_VAR_SUPPORT
  1200. // Data variable name.
  1201. if (NameMatches ("data_var_name"))
  1202. return InsertDataVarName (Section);
  1203. else
  1204. #endif /* DATA_VAR_SUPPORT */
  1205. // Nostub-specific formats.
  1206. if (NameMatches ("nostub_comments"))
  1207. return InsertNostubComments (Section);
  1208. // Kernel-specific formats.
  1209. else if (NameMatches ("kernel_relocs"))
  1210. return InsertKernelRelocs (Section, NULL);
  1211. else if (NameMatches ("kernel_bss_refs"))
  1212. return InsertKernelSectionRefs (Section, Program->BSSSection, AlwaysTerminate);
  1213. else if (NameMatches ("kernel_data_refs"))
  1214. return InsertKernelSectionRefs (Section, Program->DataSection, AlwaysTerminate);
  1215. else if (NameMatches ("kernel_rom_calls"))
  1216. return InsertKernelROMCalls (Section);
  1217. else if (NameMatches ("kernel_ram_calls"))
  1218. return InsertKernelRAMCalls (Section);
  1219. else if (NameMatches ("kernel_libs"))
  1220. return InsertKernelLibraries (Section);
  1221. else if (NameMatches ("kernel_exports"))
  1222. return InsertKernelExports (Section, TRUE);
  1223. #ifdef FARGO_SUPPORT
  1224. // Fargo-specific formats.
  1225. else if (NameMatches ("fargo_exports"))
  1226. return InsertKernelExports (Section, FALSE);
  1227. else if (NameMatches ("fargo020_bss_refs"))
  1228. return InsertKernelSectionRefs (Section, Program->BSSSection, TRUE);
  1229. else if (NameMatches ("fargo020_libs"))
  1230. return InsertFargo020Libraries (Section);
  1231. #endif /* FARGO_SUPPORT */
  1232. // PreOS-specific formats.
  1233. else if (NameMatches ("preos_compressed_tables"))
  1234. return InsertPreOsCompressedTables (Section);
  1235. // Other compressed formats.
  1236. else
  1237. {
  1238. char *ReferenceName = malloc ((sizeof (SYMPF_BUILTIN) - 1) + strlen (Name) + sizeof ("_ref"));
  1239. if (ReferenceName)
  1240. {
  1241. // Build the reference symbol name: "__ld_" Name "_ref".
  1242. strcpy (ReferenceName, SYMPF_BUILTIN);
  1243. strcat (ReferenceName, Name);
  1244. strcat (ReferenceName, "_ref");
  1245. {
  1246. LOCATION Reference = {NULL, ReferenceName, 0, FALSE};
  1247. // Try to find a reference symbol. If none is found, use
  1248. // the program entry point.
  1249. Section->Relocs.UnresolvedCount++;
  1250. if (!(ResolveLocation (Program, Section, &Reference)))
  1251. {
  1252. FreeLocationSymbolName (Section, &Reference);
  1253. Reference = Program->EntryPoint;
  1254. }
  1255. #ifdef FARGO_SUPPORT
  1256. // Fargo-specific formats.
  1257. if (NameMatches ("fargo021_relocs"))
  1258. return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
  1259. else if (NameMatches ("fargo021_bss_refs"))
  1260. return InsertFargo021SectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1261. else if (NameMatches ("fargo021_libs"))
  1262. return InsertFargo021Libraries (Section, MergedSection, &Reference);
  1263. #endif /* FARGO_SUPPORT */
  1264. // Compressed relocation tables using our own format.
  1265. else if (NameMatches ("compressed_relocs"))
  1266. return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
  1267. else if (NameMatches ("compressed_bss_refs"))
  1268. return InsertCompressedSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1269. else if (NameMatches ("compressed_data_refs"))
  1270. return InsertCompressedSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
  1271. else if (NameMatches ("compressed_rom_calls"))
  1272. return InsertCompressedROMCalls (Section, MergedSection, &Reference);
  1273. // Compressed relocation tables using our own mlink-style format.
  1274. else if (NameMatches ("mlink_relocs"))
  1275. return InsertMlinkRelocs (Section, NULL, MergedSection, &Reference);
  1276. else if (NameMatches ("mlink_bss_refs"))
  1277. return InsertMlinkSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1278. else if (NameMatches ("mlink_data_refs"))
  1279. return InsertMlinkSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
  1280. else if (NameMatches ("mlink_rom_calls"))
  1281. return InsertMlinkROMCalls (Section, MergedSection, &Reference);
  1282. else
  1283. Warning (GetFileName (Section, Section->Size), "Unrecognized insertion `%s'.", Name);
  1284. }
  1285. }
  1286. else
  1287. {
  1288. Error (NULL, "Out of memory.");
  1289. return FALSE;
  1290. }
  1291. }
  1292. return TRUE;
  1293. }