special.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441
  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. #ifdef FLASH_OS_SUPPORT
  308. && Program->Type != PT_FLASH_OS
  309. #endif /* FLASH_OS_SUPPORT */
  310. ) Result = Result && AddGlobalImport (Program, "__initialize_bss");
  311. // Handle BSS section if any.
  312. if (Program->BSSSection && (!(Program->BSSSection->Handled)))
  313. {
  314. GLOBAL_IMPORT *Import = CreateGlobalImport (Program, "__handle_bss");
  315. if (Import)
  316. {
  317. // This is the import that will mark the BSS section as handled
  318. // if it succeeds.
  319. Program->BSSImport = Import;
  320. // Try to resolve it against available archives.
  321. ResolveGlobalImport (Program, Import);
  322. // The BSS section is simply merged into the rest if it is not
  323. // handled.
  324. Import->Succeeded = TRUE;
  325. }
  326. else
  327. Result = FALSE;
  328. }
  329. // Handle absolute relocs if there are any.
  330. for_each (TempSection, Program->Sections)
  331. {
  332. BOOLEAN Done = FALSE;
  333. RELOC *TempReloc;
  334. for_each (TempReloc, TempSection->Relocs)
  335. {
  336. if ((!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled)))))
  337. {
  338. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_relocs");
  339. if (Import)
  340. // Relocs are either handled by the export format, or a
  341. // warning is emitted.
  342. Import->Succeeded = TRUE;
  343. else
  344. Result = FALSE;
  345. Done = TRUE;
  346. break;
  347. }
  348. }
  349. if (Done)
  350. break;
  351. }
  352. // Handle ROM calls if there are any.
  353. for_each (TempSection, Program->Sections)
  354. {
  355. if (!(IsEmpty (TempSection->ROMCalls)))
  356. {
  357. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_rom_calls");
  358. if (Import)
  359. // ROM calls are either handled by the export format, or a
  360. // warning is emitted.
  361. Import->Succeeded = TRUE;
  362. else
  363. Result = FALSE;
  364. break;
  365. }
  366. }
  367. // Handle RAM calls if there are any.
  368. for_each (TempSection, Program->Sections)
  369. {
  370. if (!(IsEmpty (TempSection->RAMCalls)))
  371. {
  372. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_ram_calls");
  373. if (Import)
  374. // RAM calls are either handled by the export format, or a
  375. // warning is emitted.
  376. Import->Succeeded = TRUE;
  377. else
  378. Result = FALSE;
  379. break;
  380. }
  381. }
  382. // Handle libraries if any libraries are referenced.
  383. if (!(IsEmpty (Program->Libraries)))
  384. {
  385. GLOBAL_IMPORT *Import = AddGlobalImport (Program, "__handle_libraries");
  386. if (Import)
  387. // Libraries are either handled by the export format, or a
  388. // warning is emitted.
  389. Import->Succeeded = TRUE;
  390. else
  391. Result = FALSE;
  392. }
  393. // Handle _nostub comments if any.
  394. if ((Program->Type == PT_NATIVE) || (Program->Type == PT_NOSTUB))
  395. {
  396. BOOLEAN NostubComments = FALSE;
  397. for_each (TempSection, Program->Sections)
  398. {
  399. SYMBOL *TempSymbol;
  400. for_each (TempSymbol, TempSection->Symbols)
  401. {
  402. if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, "_nostub_data__", sizeof ("_nostub_data__") - 1))))
  403. {
  404. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + sizeof ("_nostub_") - 1);
  405. if (ExportNumber >= 0)
  406. {
  407. NostubComments = TRUE;
  408. TempSection->Essential = TRUE;
  409. break;
  410. }
  411. }
  412. }
  413. }
  414. if (NostubComments)
  415. Result = Result && AddGlobalImport (Program, "__nostub_comment_header");
  416. }
  417. #ifdef DATA_VAR_SUPPORT
  418. // Handle data variable if desired.
  419. if (Program->DataVarInfo->Name && Program->DataSection)
  420. {
  421. Result = Result && (AddGlobalImport (Program, "__handle_data_var"));
  422. if (Program->DataVarInfo->CreateCopy)
  423. {
  424. Result = Result && (AddGlobalImport (Program, "__data_var_create_copy"));
  425. if (Program->DataVarInfo->CopyOnlyIfArchived)
  426. Result = Result && (AddGlobalImport (Program, "__data_var_copy_if_archived"));
  427. }
  428. }
  429. #endif /* DATA_VAR_SUPPORT */
  430. return Result;
  431. }
  432. // If the reloc or its relation point to a special ld-exported symbol,
  433. // change it to the appropriate value if possible. FALSE is returned
  434. // only if it is not a special symbol location, or if there was an error.
  435. BOOLEAN ResolveSpecialSymbolReloc (RELOC *Reloc, BOOLEAN *TryAgain)
  436. {
  437. // At first, resolve the relation, because if this is a built-in
  438. // number, we cannot write it into the section contents directly,
  439. // but we have to subtract it from FixedOffset.
  440. BOOLEAN Result = ResolveSpecialSymbolRelocRelation (Reloc, TryAgain);
  441. // Now resolve the target.
  442. return (ResolveSpecialSymbolRelocTarget (Reloc, TryAgain) ? Result : FALSE);
  443. }
  444. // If the reloc points to a special ld-exported symbol, change it to the
  445. // appropriate value if possible. FALSE is returned only if it is not a
  446. // special symbol reloc, or if there was an error.
  447. BOOLEAN ResolveSpecialSymbolRelocTarget (RELOC *Reloc, BOOLEAN *TryAgain)
  448. {
  449. BOOLEAN Result = FALSE;
  450. SECTION *Section = Reloc->Parent;
  451. LOCATION *Location = &(Reloc->Target);
  452. // If the relation is an unresolved reference to a builtin number,
  453. // do not even try to resolve the target. This would only cause
  454. // trouble, since we would need to handle it immediately if it
  455. // resolved to a number. There will be another call to this anyway
  456. // after the relation has finally been resolved.
  457. // Usually, we would at least need to set the Target.Builtin flag.
  458. // However, currently all tests which check for Target.Builtin also
  459. // check for Relation or Relative in general. If this ever changes,
  460. // this code will break.
  461. if (Reloc->Relation && Reloc->Relation->Builtin)
  462. return TRUE;
  463. if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
  464. {
  465. // If it has resolved to a number, write it into the section
  466. // contents.
  467. if (!(Location->Symbol || Location->SymbolName))
  468. {
  469. if (Reloc->Relation)
  470. Warning (GetFileName (Section, Reloc->Location), "Ignoring invalid negative reference to `%s' at 0x%lX.", Reloc->Relation->SymbolName, (long) Reloc->Location);
  471. if ((Reloc->Location >= 0) && (Reloc->Location + Reloc->Size <= Section->Size))
  472. {
  473. // Add the target offset (to support things such as "__ld_xxx+1").
  474. OFFSET NewValue = Location->Offset + Reloc->FixedOffset;
  475. if (Reloc->Relative)
  476. 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);
  477. // Check if the section contents at the reloc are zero.
  478. if (!(IsZeroDataRange (Section, Reloc->Location, Reloc->Location + Reloc->Size)))
  479. 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);
  480. // Resolve the reloc by writing the value into the section.
  481. Result = AddTI (Section->Data + Reloc->Location, Reloc->Size, NewValue, TRUE, TRUE);
  482. if (!Result)
  483. 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);
  484. }
  485. else
  486. {
  487. Warning (GetFileName (Section, Reloc->Location), "Removing reloc at 0x%lX to `%s' outside of section.", (long) Reloc->Location, Reloc->Target.SymbolName);
  488. Result = TRUE;
  489. }
  490. FreeReloc (Reloc);
  491. }
  492. else
  493. Result = TRUE;
  494. }
  495. return Result;
  496. }
  497. // If the reloc's relation points to a special ld-exported symbol,
  498. // change it to the appropriate value if possible. FALSE is returned
  499. // only if it is not a special symbol location, or if there was an error.
  500. BOOLEAN ResolveSpecialSymbolRelocRelation (RELOC *Reloc, BOOLEAN *TryAgain)
  501. {
  502. BOOLEAN Result = FALSE;
  503. SECTION *Section = Reloc->Parent;
  504. LOCATION *Location = Reloc->Relation;
  505. if (Reloc->Relation)
  506. {
  507. // Try to resolve the relation.
  508. if (ResolveSpecialSymbolLocation (Section, Location, TryAgain))
  509. {
  510. // Check if it has really been resolved.
  511. BOOLEAN Resolved = (Location->Symbol != NULL);
  512. // If it has been resolved to a number, subtract it from
  513. // FixedOffset.
  514. if (!(Location->Symbol || Location->SymbolName))
  515. {
  516. Reloc->FixedOffset -= Location->Offset;
  517. FreeRelocRelation (Reloc);
  518. Resolved = TRUE;
  519. }
  520. Result = TRUE;
  521. }
  522. }
  523. return Result;
  524. }
  525. // If the location points to a special ld-exported symbol, change it to the
  526. // appropriate value if possible. FALSE is returned only if it is not a
  527. // special symbol location, or if there was an error.
  528. // Warning: If the special symbol resolves to a number, Location->Symbol and
  529. // Location->SymbolName will both be NULL, and Location->Offset will contain
  530. // the number.
  531. BOOLEAN ResolveSpecialSymbolLocation (SECTION *Section, LOCATION *Location, BOOLEAN *TryAgain)
  532. {
  533. const char *SymName = Location->SymbolName;
  534. BOOLEAN SymNameMatches (const char *Name)
  535. {
  536. return (!(strcmp (SymName, Name)));
  537. }
  538. // Locations that are already resolved do not need any treatment.
  539. if (Location->Symbol)
  540. return FALSE;
  541. // All special symbols start with '_'.
  542. if (SymName && (SymName [0] == '_'))
  543. {
  544. PROGRAM *Program = Section->Parent;
  545. BOOLEAN SetToEntryPoint = FALSE;
  546. OFFSET NewValue = 0;
  547. SymName++;
  548. // All built-in symbols start with "__ld_".
  549. if (!(strncmp (SymName, SYMPF_BUILTIN + 1, sizeof (SYMPF_BUILTIN) - 2)))
  550. {
  551. SIZE SymNameLength;
  552. BOOLEAN HasValue = FALSE;
  553. SYMBOL *NewSymbol = NULL;
  554. OFFSET NewTargetOffset = 0;
  555. SECTION *TempSection;
  556. // Skip the "__ld_" prefix.
  557. SymName += sizeof (SYMPF_BUILTIN) - 2;
  558. SymNameLength = strlen (SymName);
  559. // Find (but do not resolve) calculator constants.
  560. if (IsCalcBuiltinLocation (Location))
  561. ;
  562. // Resolve references to insertions.
  563. else if (!(strncmp (SymName, SYMPF_INSERT, sizeof (SYMPF_INSERT) - 1)))
  564. {
  565. if ((!(TempSection = Program->MainSection))
  566. || (!(NewSymbol = HandleAutoInsertion (TempSection, Location->SymbolName))))
  567. return TRUE;
  568. }
  569. // Resolve "has_...s".
  570. else if ((!(strncmp (SymName, "has_", sizeof ("has_") - 1))) && (SymName [SymNameLength - 1] == 's'))
  571. {
  572. if (Program->ResolveAllBuiltins)
  573. {
  574. Program->Frozen = TRUE;
  575. if (GetBuiltinValue (Program, SymName + (sizeof ("has_") - 1), SymNameLength - 1 - (sizeof ("has_") - 1), &NewValue, -1))
  576. HasValue = TRUE;
  577. }
  578. }
  579. // Resolve "..._count".
  580. else if ((SymNameLength > ((SIZE) (sizeof ("_count") - 1))) && (!(strcmp (SymName + SymNameLength - (sizeof ("_count") - 1), "_count"))))
  581. {
  582. if (Program->ResolveAllBuiltins)
  583. {
  584. Program->Frozen = TRUE;
  585. if (GetBuiltinValue (Program, SymName, SymNameLength - (sizeof ("_count") - 1), &NewValue, 0))
  586. HasValue = TRUE;
  587. }
  588. }
  589. else if (SymNameMatches ("entry_point"))
  590. SetToEntryPoint = TRUE;
  591. else if (SymNameMatches ("entry_point_plus_0x8000"))
  592. {
  593. SetToEntryPoint = TRUE;
  594. NewValue = 0x8000;
  595. }
  596. else if (SymNameMatches ("constructors_start"))
  597. {
  598. if (!(NewSymbol = Program->Constructors.Start))
  599. return TRUE;
  600. }
  601. else if (SymNameMatches ("constructors_end"))
  602. {
  603. if (!(NewSymbol = Program->Constructors.End))
  604. return TRUE;
  605. }
  606. else if (SymNameMatches ("constructors_size"))
  607. {
  608. if (Program->Constructors.Start && Program->Constructors.End)
  609. {
  610. NewValue = Program->Constructors.End->Location - Program->Constructors.Start->Location;
  611. HasValue = TRUE;
  612. }
  613. else if (Program->ResolveAllBuiltins)
  614. HasValue = TRUE;
  615. }
  616. else if (SymNameMatches ("destructors_start"))
  617. {
  618. if (!(NewSymbol = Program->Destructors.Start))
  619. return TRUE;
  620. }
  621. else if (SymNameMatches ("destructors_end"))
  622. {
  623. if (!(NewSymbol = Program->Destructors.End))
  624. return TRUE;
  625. }
  626. else if (SymNameMatches ("destructors_size"))
  627. {
  628. if (Program->Destructors.Start && Program->Destructors.End)
  629. {
  630. NewValue = Program->Destructors.End->Location - Program->Destructors.Start->Location;
  631. HasValue = TRUE;
  632. }
  633. else if (Program->ResolveAllBuiltins)
  634. HasValue = TRUE;
  635. }
  636. else if (SymNameMatches ("data_start"))
  637. {
  638. if (Program->DataSection)
  639. NewSymbol = Program->DataSection->SectionSymbol;
  640. else
  641. return TRUE;
  642. }
  643. else if (SymNameMatches ("data_end"))
  644. {
  645. if (Program->DataSection)
  646. {
  647. NewSymbol = Program->DataSection->SectionSymbol;
  648. NewTargetOffset = Program->DataSection->Size;
  649. }
  650. else
  651. return TRUE;
  652. }
  653. else if (SymNameMatches ("data_size"))
  654. {
  655. if (Program->DataSection)
  656. {
  657. NewValue = Program->DataSection->Size;
  658. HasValue = TRUE;
  659. }
  660. else if (Program->ResolveAllBuiltins)
  661. HasValue = TRUE;
  662. }
  663. else if (SymNameMatches ("bss_start"))
  664. {
  665. if (Program->BSSSection)
  666. NewSymbol = Program->BSSSection->SectionSymbol;
  667. else
  668. return TRUE;
  669. }
  670. else if (SymNameMatches ("bss_end"))
  671. {
  672. if (Program->BSSSection)
  673. {
  674. NewSymbol = Program->BSSSection->SectionSymbol;
  675. NewTargetOffset = Program->BSSSection->Size;
  676. }
  677. else
  678. return TRUE;
  679. }
  680. else if (SymNameMatches ("bss_even_end"))
  681. {
  682. if (Program->BSSSection)
  683. {
  684. NewSymbol = Program->BSSSection->SectionSymbol;
  685. NewTargetOffset = (OFFSET) ((unsigned long) (Program->BSSSection->Size + 1) & ~1UL);
  686. }
  687. else
  688. return TRUE;
  689. }
  690. else if (SymNameMatches ("bss_size"))
  691. {
  692. if (Program->BSSSection)
  693. {
  694. NewValue = Program->BSSSection->Size;
  695. HasValue = TRUE;
  696. }
  697. else if (Program->ResolveAllBuiltins)
  698. HasValue = TRUE;
  699. }
  700. else if (SymNameMatches ("file_version"))
  701. {
  702. if (Program->ResolveAllBuiltins || Program->Version)
  703. {
  704. NewValue = Program->Version;
  705. HasValue = TRUE;
  706. }
  707. }
  708. else if (SymNameMatches ("link_time_year"))
  709. {
  710. if (Program->ResolveAllBuiltins)
  711. {
  712. NewValue = Program->LinkTime.Year;
  713. HasValue = TRUE;
  714. }
  715. }
  716. else if (SymNameMatches ("link_time_month"))
  717. {
  718. if (Program->ResolveAllBuiltins)
  719. {
  720. NewValue = Program->LinkTime.Month;
  721. HasValue = TRUE;
  722. }
  723. }
  724. else if (SymNameMatches ("link_time_day"))
  725. {
  726. if (Program->ResolveAllBuiltins)
  727. {
  728. NewValue = Program->LinkTime.Day;
  729. HasValue = TRUE;
  730. }
  731. }
  732. else if (SymNameMatches ("link_time_timestamp"))
  733. {
  734. if (Program->ResolveAllBuiltins)
  735. {
  736. NewValue = Program->LinkTime.LinkTime;
  737. HasValue = TRUE;
  738. }
  739. }
  740. else if (SymNameMatches ("kernel_flags"))
  741. {
  742. if (Program->ResolveAllBuiltins)
  743. {
  744. NewValue = Program->KernelFlags;
  745. HasValue = TRUE;
  746. }
  747. }
  748. else if (SymNameMatches ("kernel_bss_table"))
  749. {
  750. if (Program->BSSSection)
  751. {
  752. strcpy ((char *) (Location->SymbolName), "__kernel_bss_table");
  753. if (TryAgain)
  754. *TryAgain = TRUE;
  755. // This prevents the section from being merged, and prevents
  756. // relocs to it from being emitted.
  757. Program->BSSSection->Handled = TRUE;
  758. return FALSE;
  759. }
  760. else if (Program->ResolveAllBuiltins)
  761. SetToEntryPoint = TRUE;
  762. }
  763. else if (SymNameMatches ("program_size"))
  764. {
  765. if (Program->ResolveAllBuiltins && Program->MainSection)
  766. {
  767. NewValue = Program->MainSection->Size;
  768. HasValue = TRUE;
  769. }
  770. else
  771. return TRUE;
  772. }
  773. #ifdef FLASH_OS_SUPPORT
  774. else if (SymNameMatches ("archive_start"))
  775. {
  776. if (Program->ResolveAllBuiltins && Program->MainSection)
  777. {
  778. SetToEntryPoint = TRUE;
  779. NewValue = (OFFSET) ((unsigned long) (Program->MainSection->Size + 65535) & ~65535UL) - 0x02000;
  780. }
  781. else
  782. return TRUE;
  783. }
  784. #endif
  785. else if (SymNameMatches ("kernel_export_table"))
  786. {
  787. BOOLEAN HasExports = FALSE;
  788. for_each (TempSection, Program->Sections)
  789. {
  790. SYMBOL *TempSymbol;
  791. for_each (TempSymbol, TempSection->Symbols)
  792. {
  793. if (TempSymbol->Exported)
  794. {
  795. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
  796. if (ExportNumber >= 0)
  797. {
  798. HasExports = TRUE;
  799. TempSection->Essential = TRUE;
  800. break;
  801. }
  802. }
  803. }
  804. }
  805. if (HasExports)
  806. {
  807. strcpy ((char *) (Location->SymbolName), "__kernel_export_table");
  808. if (TryAgain)
  809. *TryAgain = TRUE;
  810. return FALSE;
  811. }
  812. else if (Program->ResolveAllBuiltins)
  813. SetToEntryPoint = TRUE;
  814. }
  815. #ifdef DATA_VAR_SUPPORT
  816. else if (SymNameMatches ("data_var_name_end"))
  817. {
  818. // Point the reloc to the terminating zero byte of the name.
  819. if (Program->DataVarInfo->Name)
  820. {
  821. strcpy ((char *) (Location->SymbolName), "__data_var_name_start");
  822. Location->Offset += strlen (Program->DataVarInfo->Name) + 1;
  823. if (TryAgain)
  824. *TryAgain = TRUE;
  825. return FALSE;
  826. }
  827. }
  828. #endif /* DATA_VAR_SUPPORT */
  829. else
  830. return FALSE;
  831. if (!SetToEntryPoint)
  832. {
  833. if (HasValue)
  834. {
  835. // Point the location to the new value.
  836. Location->Symbol = NULL;
  837. FreeLocationSymbolName (Section, Location);
  838. Location->Offset += NewValue;
  839. }
  840. else if (NewSymbol)
  841. {
  842. // Point the location to the new symbol.
  843. Location->Symbol = NewSymbol;
  844. FreeLocationSymbolName (Section, Location);
  845. Location->Offset += NewTargetOffset;
  846. }
  847. else
  848. Location->Builtin = TRUE;
  849. return TRUE;
  850. }
  851. }
  852. // If this is a reloc to a kernel-specific symbol, point it to the
  853. // entry point. The result of this is that the reloc's value
  854. // becomes 0 if the reloc was made up by something like
  855. // _exit-__kernel_entry_point.
  856. else if (SymNameMatches ("exit") || SymNameMatches ("comment") || SymNameMatches ("extraram") || SymNameMatches ("library"))
  857. SetToEntryPoint = TRUE;
  858. if (SetToEntryPoint)
  859. {
  860. if (Program->EntryPoint.Symbol)
  861. {
  862. Location->Symbol = Program->EntryPoint.Symbol;
  863. FreeLocationSymbolName (Section, Location);
  864. Location->Offset += Program->EntryPoint.Offset + NewValue;
  865. }
  866. return TRUE;
  867. }
  868. }
  869. return FALSE;
  870. }
  871. // Count the items for a specific built-in symbol, specified by SymName
  872. // and SymNameLength. If TrueValue is nonzero, items are not counted,
  873. // but NewValue is set to this value if at least one item was found. In
  874. // that case, if Program->ResolveAllBuiltins is false, NewValue may be
  875. // unchanged even though there are some items; you need to check back
  876. // later when Program->ResolveAllBuiltins is true.
  877. BOOLEAN GetBuiltinValue (PROGRAM *Program, const char *SymName, SIZE SymNameLength, OFFSET *NewValue, OFFSET TrueValue)
  878. {
  879. #define Count(n,op,code) \
  880. ({ \
  881. register OFFSET n__ = (n); \
  882. if (TrueValue) \
  883. { \
  884. if (n__) \
  885. { \
  886. *NewValue = TrueValue; \
  887. code; \
  888. } \
  889. } \
  890. else \
  891. *NewValue op n__; \
  892. })
  893. #define SetCounter(n) (Count ((n), =, (void) 0))
  894. #define IncreaseCounter(n) (Count ((n), +=, break))
  895. BOOLEAN SymNameMatches (const char *Name)
  896. {
  897. return (!(strncmp (SymName, Name, SymNameLength)));
  898. }
  899. SECTION *TempSection;
  900. RELOC *TempReloc;
  901. SYMBOL *TempSymbol;
  902. if (SymNameMatches ("constructor"))
  903. {
  904. if (Program->Constructors.Start && Program->Constructors.End)
  905. SetCounter ((Program->Constructors.End->Location - Program->Constructors.Start->Location) >> 2);
  906. }
  907. else if (SymNameMatches ("destructor"))
  908. {
  909. if (Program->Destructors.Start && Program->Destructors.End)
  910. SetCounter ((Program->Destructors.End->Location - Program->Destructors.Start->Location) >> 2);
  911. }
  912. else if (SymNameMatches ("reloc"))
  913. {
  914. // Count all absolute relocs.
  915. // Relative relocs will either be resolved completely or
  916. // produce errors.
  917. for_each (TempSection, Program->Sections)
  918. {
  919. IncreaseCounter (TempSection->Relocs.EmittedCount);
  920. // Since relocs may be removed, if ResolveAllBuiltins
  921. // is false, do not handle TrueValue.
  922. if ((!TrueValue) || Program->ResolveAllBuiltins)
  923. {
  924. for_each (TempReloc, TempSection->Relocs)
  925. if (!(TempReloc->Relative || TempReloc->Target.Builtin || (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent->Handled))))
  926. IncreaseCounter (1);
  927. }
  928. }
  929. }
  930. else if (SymNameMatches ("data_ref"))
  931. {
  932. if (Program->DataSection)
  933. {
  934. // Count all absolute relocs to the data section.
  935. for_each (TempSection, Program->Sections)
  936. for_each (TempReloc, TempSection->Relocs)
  937. if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->DataSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
  938. IncreaseCounter (1);
  939. }
  940. }
  941. else if (SymNameMatches ("bss_ref"))
  942. {
  943. if (Program->BSSSection)
  944. {
  945. // Count all absolute relocs to the BSS section.
  946. for_each (TempSection, Program->Sections)
  947. for_each (TempReloc, TempSection->Relocs)
  948. if (TempReloc->Target.Symbol && (TempReloc->Target.Symbol->Parent == Program->BSSSection) && (!(TempReloc->Relative || TempReloc->Target.Builtin)))
  949. IncreaseCounter (1);
  950. }
  951. }
  952. else if (SymNameMatches ("rom_call"))
  953. {
  954. for_each (TempSection, Program->Sections)
  955. IncreaseCounter (CountItems (TempSection->ROMCalls, ROM_CALL));
  956. }
  957. else if (SymNameMatches ("ram_call"))
  958. {
  959. for_each (TempSection, Program->Sections)
  960. IncreaseCounter (CountItems (TempSection->RAMCalls, RAM_CALL));
  961. }
  962. else if (SymNameMatches ("lib"))
  963. SetCounter (CountItems (Program->Libraries, LIBRARY));
  964. else if (SymNameMatches ("referenced_lib"))
  965. SetCounter (Program->Libraries.ReferencedCount);
  966. else if (SymNameMatches ("export"))
  967. {
  968. // The number of exports is equal to the highest export number + 1.
  969. for_each (TempSection, Program->Sections)
  970. {
  971. for_each (TempSymbol, TempSection->Symbols)
  972. {
  973. if (TempSymbol->Exported)
  974. {
  975. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name);
  976. if ((ExportNumber >= 0) && (*NewValue < ExportNumber + 1))
  977. Count (ExportNumber + 1, =, break);
  978. }
  979. }
  980. }
  981. }
  982. else if (SymNameMatches ("nostub_comment"))
  983. {
  984. for_each (TempSection, Program->Sections)
  985. {
  986. for_each (TempSymbol, TempSection->Symbols)
  987. {
  988. if (TempSymbol->Exported && (!(strncmp (TempSymbol->Name, SYMPF_NOSTUB_DATA, sizeof (SYMPF_NOSTUB_DATA) - 1))))
  989. {
  990. OFFSET ExportNumber = GetExportNumber (TempSymbol->Name + (sizeof (SYMPF_NOSTUB_DATA_START) - 1));
  991. if (ExportNumber >= 0)
  992. IncreaseCounter (1);
  993. }
  994. }
  995. }
  996. }
  997. else
  998. return FALSE;
  999. #undef IncreaseCounter
  1000. #undef SetCounter
  1001. #undef Count
  1002. return TRUE;
  1003. }
  1004. // If the given symbol name belongs to a calculator-specific builtin
  1005. // symbol, return a pointer to the part of it that holds the values.
  1006. static const char *GetCalcBuiltinValues (const char *SymName)
  1007. {
  1008. if (!(strncmp (SymName, SYMPF_BUILTIN_CALC_CONST, sizeof (SYMPF_BUILTIN_CALC_CONST) - 1)))
  1009. {
  1010. return (SymName + (sizeof (SYMPF_BUILTIN_CALC_CONST) - 1));
  1011. }
  1012. return NULL;
  1013. }
  1014. // Check if the given location points to a calculator-specific builtin
  1015. // symbol.
  1016. BOOLEAN IsCalcBuiltinLocation (const LOCATION *Location)
  1017. {
  1018. return (Location->SymbolName && (GetCalcBuiltinValues (Location->SymbolName) || (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))));
  1019. }
  1020. // Return whether the reloc can be resolved to a calculator-specific value.
  1021. // ResolveSpecialSymbol or something related must have been called on the
  1022. // reloc at least once.
  1023. BOOLEAN IsPlainCalcBuiltin (const RELOC *Reloc)
  1024. {
  1025. // To improve speed, check whether the target and relation (if it exists)
  1026. // are builtin symbols.
  1027. if (Reloc->Target.Builtin && ((!(Reloc->Relation)) || Reloc->Relation->Builtin))
  1028. {
  1029. // Check the target.
  1030. if (IsCalcBuiltinLocation (&(Reloc->Target)))
  1031. {
  1032. // If there is a relation, check it.
  1033. if (Reloc->Relation)
  1034. return IsCalcBuiltinLocation (Reloc->Relation);
  1035. // Otherwise, the reloc may not be relative, since that would
  1036. // mean that it cannot be resolved to a number.
  1037. else
  1038. return (!(Reloc->Relative));
  1039. }
  1040. }
  1041. return FALSE;
  1042. }
  1043. // If the location can be resolved to a calculator-specific value, get the
  1044. // value for the specified calculator.
  1045. // If IsCalcBuiltinLocation returned a positive result for this reloc, this
  1046. // function will not return a negative result.
  1047. BOOLEAN GetCalcBuiltinLocationValue (const LOCATION *Location, ProgramCalcs DestCalc, IMAX *Value)
  1048. {
  1049. // Basic sanity checks.
  1050. if (Value && Location->SymbolName)
  1051. {
  1052. // Special case: __ld_hardware_id
  1053. if (!(strcmp (Location->SymbolName, SYM_BUILTIN_HARDWARE_ID)))
  1054. {
  1055. switch (DestCalc)
  1056. {
  1057. case CALC_TI89:
  1058. *Value = 3;
  1059. break;
  1060. case CALC_TI89 | CALC_FLAG_TITANIUM:
  1061. *Value = 9;
  1062. break;
  1063. case CALC_TI92PLUS:
  1064. *Value = 1;
  1065. break;
  1066. case CALC_V200:
  1067. *Value = 8;
  1068. break;
  1069. default:
  1070. Warning (NULL, SYM_BUILTIN_HARDWARE_ID " not defined for this calculator.");
  1071. *Value = 0;
  1072. }
  1073. *Value += Location->Offset;
  1074. return TRUE;
  1075. }
  1076. else
  1077. {
  1078. // Get the part of the symbol name that holds the values,
  1079. // separated by '_'.
  1080. const char *Values = GetCalcBuiltinValues (Location->SymbolName);
  1081. if (Values)
  1082. {
  1083. // AND out the calculator flags.
  1084. DestCalc &= ~CALC_FLAG_TITANIUM;
  1085. // While we still have at least one value left...
  1086. while (Values)
  1087. {
  1088. // Get the end of the value string.
  1089. const char *ValueEnd = strchr (Values, '_');
  1090. SIZE ValueSize = ValueEnd ? (SIZE) (ValueEnd - Values) : (SIZE) (strlen (Values));
  1091. // If this is the value that belongs to the current calculator,
  1092. // extract the value and return.
  1093. if (DestCalc == 1)
  1094. {
  1095. char *EndPtr = NULL;
  1096. // Create a copy of the value, with a terminating zero byte.
  1097. char ValueStr[ValueSize+1];
  1098. strncpy (ValueStr, Values, ValueSize);
  1099. ValueStr [ValueSize] = 0;
  1100. // Convert this string into a number and return it.
  1101. *Value = strtoul (ValueStr, &EndPtr, 0);
  1102. if (EndPtr && *EndPtr)
  1103. Warning (NULL, "Invalid number `%s' in `%s'.", ValueStr, Location->SymbolName);
  1104. *Value += Location->Offset;
  1105. return TRUE;
  1106. }
  1107. // Advance to the next value.
  1108. Values = ValueEnd ? ValueEnd + 1 : NULL;
  1109. // Advance to the next calculator.
  1110. DestCalc >>= 1;
  1111. }
  1112. // No more values were found, but the function did not exit yet.
  1113. Warning (NULL, "Calculator constant `%s' contains too few values.", Location->SymbolName);
  1114. *Value = 0;
  1115. // We have to return a positive result anyway because
  1116. // IsCalcBuiltinLocation would as well.
  1117. return TRUE;
  1118. }
  1119. }
  1120. }
  1121. return FALSE;
  1122. }
  1123. // If the reloc can be resolved to a calculator-specific value, get the
  1124. // value for the specified calculator.
  1125. // The return value is the same as for IsPlainCalcBuiltin.
  1126. BOOLEAN GetCalcBuiltinValue (const RELOC *Reloc, ProgramCalcs DestCalc, IMAX *Value)
  1127. {
  1128. if (Value)
  1129. {
  1130. // Get the value for the target.
  1131. if (GetCalcBuiltinLocationValue (&(Reloc->Target), DestCalc, Value))
  1132. {
  1133. // If there is a relation, subtract its value.
  1134. if (Reloc->Relation)
  1135. {
  1136. IMAX RelationValue;
  1137. if (!(GetCalcBuiltinLocationValue (Reloc->Relation, DestCalc, &RelationValue)))
  1138. return FALSE;
  1139. *Value -= RelationValue;
  1140. }
  1141. // Otherwise, the reloc may not be relative
  1142. // (see IsPlainCalcBuiltin).
  1143. else if (Reloc->Relative)
  1144. return FALSE;
  1145. *Value += Reloc->FixedOffset;
  1146. return TRUE;
  1147. }
  1148. }
  1149. return FALSE;
  1150. }
  1151. // If required by some special symbol(s) at the end of the section,
  1152. // modify the contents of the section.
  1153. // This can be used to insert special items such as relocation entries.
  1154. // MergedSection specifies the (usually large) part of the program that
  1155. // has already been merged.
  1156. // If necessary, MergedSection is frozen automatically.
  1157. BOOLEAN HandleSectionContents (SECTION *Section, SECTION *MergedSection)
  1158. {
  1159. SYMBOL *Symbol;
  1160. // Search the labels at the end of the secion to find special ones.
  1161. for (Symbol = FindSymbolAtPos (Section, Section->Size, TRUE); Symbol; Symbol = GetNext (Symbol))
  1162. {
  1163. if (!(strncmp (Symbol->Name, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
  1164. return (HandleInsertion (Section, Symbol->Location, Symbol->Name + sizeof (SYMPF_BUILTIN_INSERT) - 1, MergedSection, FALSE));
  1165. }
  1166. return TRUE;
  1167. }
  1168. // Insert contents for an insertion specified by SymbolName, and return
  1169. // a symbol from where the insertion took place.
  1170. // If necessary, Section is frozen automatically.
  1171. SYMBOL *HandleAutoInsertion (SECTION *Section, const char *SymbolName)
  1172. {
  1173. if (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT, sizeof (SYMPF_BUILTIN_INSERT) - 1)))
  1174. {
  1175. CreateSectionSegment (Section);
  1176. // All insertions except compressed ones should be aligned on a 2-byte boundary.
  1177. if ((!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_COMPRESSED, sizeof (SYMPF_BUILTIN_INSERT_COMPRESSED) - 1)))
  1178. || (!(strncmp (SymbolName, SYMPF_BUILTIN_INSERT_MLINK, sizeof (SYMPF_BUILTIN_INSERT_MLINK) - 1)))
  1179. || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "fargo021_relocs")))
  1180. || (!(strcmp (SymbolName, SYMPF_BUILTIN_INSERT "preos_compressed_tables")))
  1181. || PadSection (Section, 2))
  1182. {
  1183. // Create a new symbol at the end of the section.
  1184. SYMBOL *Result = calloc (1, sizeof (SYMBOL));
  1185. if (Result)
  1186. {
  1187. Result->Parent = Section;
  1188. Result->Location = Section->Size;
  1189. strncpy (Result->Name, SymbolName, MAX_SYM_LEN);
  1190. Result->Exported = TRUE;
  1191. Append (Section->Symbols, Result);
  1192. // Insert the data.
  1193. if (AppendInsertionData (Section, SymbolName + sizeof (SYMPF_BUILTIN_INSERT) - 1, Section, TRUE))
  1194. return Result;
  1195. }
  1196. else
  1197. Error (NULL, "Out of memory.");
  1198. }
  1199. }
  1200. return NULL;
  1201. }
  1202. // Handle an insertion by cutting the section off at the specified location
  1203. // and inserting the contents specified by the name, taking into account
  1204. // that MergedSection specifies the (usually large) part of the program
  1205. // that has already been merged.
  1206. BOOLEAN HandleInsertion (SECTION *Section, OFFSET Location, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
  1207. {
  1208. if (Location == Section->Size)
  1209. return AppendInsertionData (Section, Name, MergedSection, AlwaysTerminate);
  1210. else
  1211. return TRUE;
  1212. }
  1213. // Append the data required by an insertion (specified by name) to the
  1214. // section specified by Section, taking into account that MergedSection
  1215. // specifies the (usually large) part of the program that has already
  1216. // been merged.
  1217. BOOLEAN AppendInsertionData (SECTION *Section, const char *Name, SECTION *MergedSection, BOOLEAN AlwaysTerminate)
  1218. {
  1219. BOOLEAN NameMatches (const char *InsertionName)
  1220. {
  1221. return (!(strcmp (Name, InsertionName)));
  1222. }
  1223. PROGRAM *Program = Section->Parent;
  1224. #ifdef DATA_VAR_SUPPORT
  1225. // Data variable name.
  1226. if (NameMatches ("data_var_name"))
  1227. return InsertDataVarName (Section);
  1228. else
  1229. #endif /* DATA_VAR_SUPPORT */
  1230. // Nostub-specific formats.
  1231. if (NameMatches ("nostub_comments"))
  1232. return InsertNostubComments (Section);
  1233. // Kernel-specific formats.
  1234. else if (NameMatches ("kernel_relocs"))
  1235. return InsertKernelRelocs (Section, NULL);
  1236. else if (NameMatches ("kernel_bss_refs"))
  1237. return InsertKernelSectionRefs (Section, Program->BSSSection, AlwaysTerminate);
  1238. else if (NameMatches ("kernel_data_refs"))
  1239. return InsertKernelSectionRefs (Section, Program->DataSection, AlwaysTerminate);
  1240. else if (NameMatches ("kernel_rom_calls"))
  1241. return InsertKernelROMCalls (Section);
  1242. else if (NameMatches ("kernel_ram_calls"))
  1243. return InsertKernelRAMCalls (Section);
  1244. else if (NameMatches ("kernel_libs"))
  1245. return InsertKernelLibraries (Section);
  1246. else if (NameMatches ("kernel_exports"))
  1247. return InsertKernelExports (Section, TRUE);
  1248. #ifdef FARGO_SUPPORT
  1249. // Fargo-specific formats.
  1250. else if (NameMatches ("fargo_exports"))
  1251. return InsertKernelExports (Section, FALSE);
  1252. else if (NameMatches ("fargo020_bss_refs"))
  1253. return InsertKernelSectionRefs (Section, Program->BSSSection, TRUE);
  1254. else if (NameMatches ("fargo020_libs"))
  1255. return InsertFargo020Libraries (Section);
  1256. #endif /* FARGO_SUPPORT */
  1257. // PreOS-specific formats.
  1258. else if (NameMatches ("preos_compressed_tables"))
  1259. return InsertPreOsCompressedTables (Section);
  1260. // Other compressed formats.
  1261. else
  1262. {
  1263. char *ReferenceName = malloc ((sizeof (SYMPF_BUILTIN) - 1) + strlen (Name) + sizeof ("_ref"));
  1264. if (ReferenceName)
  1265. {
  1266. // Build the reference symbol name: "__ld_" Name "_ref".
  1267. strcpy (ReferenceName, SYMPF_BUILTIN);
  1268. strcat (ReferenceName, Name);
  1269. strcat (ReferenceName, "_ref");
  1270. {
  1271. LOCATION Reference = {NULL, ReferenceName, 0, FALSE};
  1272. // Try to find a reference symbol. If none is found, use
  1273. // the program entry point.
  1274. Section->Relocs.UnresolvedCount++;
  1275. if (!(ResolveLocation (Program, Section, &Reference)))
  1276. {
  1277. FreeLocationSymbolName (Section, &Reference);
  1278. Reference = Program->EntryPoint;
  1279. }
  1280. #ifdef FARGO_SUPPORT
  1281. // Fargo-specific formats.
  1282. if (NameMatches ("fargo021_relocs"))
  1283. return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
  1284. else if (NameMatches ("fargo021_bss_refs"))
  1285. return InsertFargo021SectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1286. else if (NameMatches ("fargo021_libs"))
  1287. return InsertFargo021Libraries (Section, MergedSection, &Reference);
  1288. #endif /* FARGO_SUPPORT */
  1289. // Compressed relocation tables using our own format.
  1290. else if (NameMatches ("compressed_relocs"))
  1291. return InsertCompressedRelocs (Section, NULL, MergedSection, &Reference);
  1292. else if (NameMatches ("compressed_bss_refs"))
  1293. return InsertCompressedSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1294. else if (NameMatches ("compressed_data_refs"))
  1295. return InsertCompressedSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
  1296. else if (NameMatches ("compressed_rom_calls"))
  1297. return InsertCompressedROMCalls (Section, MergedSection, &Reference);
  1298. // Compressed relocation tables using our own mlink-style format.
  1299. else if (NameMatches ("mlink_relocs"))
  1300. return InsertMlinkRelocs (Section, NULL, MergedSection, &Reference);
  1301. else if (NameMatches ("mlink_bss_refs"))
  1302. return InsertMlinkSectionRefs (Section, Program->BSSSection, MergedSection, &Reference);
  1303. else if (NameMatches ("mlink_data_refs"))
  1304. return InsertMlinkSectionRefs (Section, Program->DataSection, MergedSection, &Reference);
  1305. else if (NameMatches ("mlink_rom_calls"))
  1306. return InsertMlinkROMCalls (Section, MergedSection, &Reference);
  1307. else
  1308. Warning (GetFileName (Section, Section->Size), "Unrecognized insertion `%s'.", Name);
  1309. }
  1310. }
  1311. else
  1312. {
  1313. Error (NULL, "Out of memory.");
  1314. return FALSE;
  1315. }
  1316. }
  1317. return TRUE;
  1318. }