special.c 43 KB

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