imp_coff.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /* imp_coff.c: Routines to import a COFF file
  2. Copyright (C) 2002-2003 Sebastian Reichelt
  3. Copyright (C) 2003-2005 Kevin Kofler
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software Foundation,
  14. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  15. #include "imp_coff.h"
  16. #ifdef COFF_SUPPORT
  17. #include "../formats/coff.h"
  18. #include "../manip.h"
  19. #include "../special.h"
  20. #include "../bincode/fix_m68k.h"
  21. #include <stdlib.h>
  22. #include <string.h>
  23. // Extra Information for a COFF Section
  24. typedef struct {
  25. SECTION *Section;
  26. char Name[COFF_SECTION_NAME_LEN+1];
  27. OFFSET VAddr;
  28. } SEC_INFO;
  29. // Extra Information for a COFF Symbol
  30. typedef struct {
  31. SYMBOL *Symbol;
  32. } SYM_INFO;
  33. // Import a COFF file into the internal data structures.
  34. BOOLEAN ImportCOFFFile (PROGRAM *Program, const I1 *File, SIZE FileSize, const char *FileName)
  35. {
  36. // Call this for a nice and clean failing exit.
  37. #define Fail() ({ if (SymInfo) free (SymInfo); if (SecInfo) free (SecInfo); return FALSE; })
  38. #define TestMem(Ptr) ({ if (!(Ptr)) { Error (FileName, "Out of memory."); Fail (); } })
  39. // Check if a given object with a given type is completely inside the file.
  40. #define IsInFile(Ptr,Type) (((const I1 *) (Ptr)) >= File && ((const I1 *) (Ptr)) + sizeof (Type) <= File + FileSize)
  41. #define TestInFile(Ptr,Type) ({ if (!(IsInFile (Ptr, Type))) { Error (FileName, "Corrupt COFF object file."); Fail (); } })
  42. // Local Variables
  43. COFF_INFO FileInfo;
  44. const COFF_HEADER *COFFHeader = (const COFF_HEADER *) File;
  45. const COFF_SECTIONS *COFFSections;
  46. const COFF_SYMBOLS *COFFSymbols;
  47. const char *COFFStringTable;
  48. SEC_INFO *SecInfo = NULL;
  49. SYM_INFO *SymInfo = NULL;
  50. BOOLEAN InitializeBSS = TRUE;
  51. BOOLEAN AllRelocs = FALSE;
  52. OFFSET CurCOFFSectionNumber, CurCOFFSymbolNumber, CurCOFFRelocNumber;
  53. // Create file information in FileInfo.
  54. CreateCoffInfo (*COFFHeader, FileInfo);
  55. // Get pointer to list of sections.
  56. COFFSections = (const COFF_SECTIONS *) (File + FileInfo.PSections);
  57. // Get pointer to list of symbols.
  58. COFFSymbols = (const COFF_SYMBOLS *) (File + FileInfo.PSymbols);
  59. // Get pointer to string table.
  60. COFFStringTable = (const char *) (File + FileInfo.PStrings);
  61. // *** Process File-Local Special Symbols ***
  62. // For each symbol...
  63. for (CurCOFFSymbolNumber = 0; CurCOFFSymbolNumber < FileInfo.SymbolCount; CurCOFFSymbolNumber++)
  64. {
  65. // Get pointer to this symbol.
  66. const COFF_SYMBOL *CurCOFFSymbol = &((*COFFSymbols) [CurCOFFSymbolNumber]);
  67. TestInFile (CurCOFFSymbol, COFF_SYMBOL);
  68. // Only process long symbol names.
  69. if (IsZero (CurCOFFSymbol->Name.StringRef.Zero))
  70. {
  71. // If the name is special, set the appropriate flag.
  72. const char *SymName = COFFStringTable + ReadTI4 (CurCOFFSymbol->Name.StringRef.StringOffset);
  73. TestInFile (SymName, char);
  74. if (!(strcmp (SymName, SYM_OMIT_BSS_INIT)))
  75. InitializeBSS = FALSE;
  76. else if (!(strcmp (SymName, SYM_ALL_RELOCS)))
  77. AllRelocs = TRUE;
  78. else if (!(strcmp (SymName, SYM_IGNORE_GLOBAL_IMPORTS)))
  79. Program->IgnoreGlobalImports = TRUE;
  80. }
  81. // Skip corresponding auxiliary symbols.
  82. CurCOFFSymbolNumber += ReadTI1 (CurCOFFSymbol->AuxSymbolCount);
  83. }
  84. // *** Import Sections ***
  85. // Create extra section information table.
  86. SecInfo = calloc (FileInfo.SectionCount, sizeof (SEC_INFO));
  87. TestMem (SecInfo);
  88. // For each section...
  89. for (CurCOFFSectionNumber = 0; CurCOFFSectionNumber < FileInfo.SectionCount; CurCOFFSectionNumber++)
  90. {
  91. OFFSET StartupNumber;
  92. // Get pointer to this section.
  93. const COFF_SECTION *CurCOFFSection = &((*COFFSections) [CurCOFFSectionNumber]);
  94. TestInFile (CurCOFFSection, COFF_SECTION);
  95. // Put name and virtual address into section information.
  96. strncpy (SecInfo[CurCOFFSectionNumber].Name, CurCOFFSection->Name, sizeof (CurCOFFSection->Name));
  97. SecInfo[CurCOFFSectionNumber].VAddr = ReadTI4 (CurCOFFSection->VirtualAddress);
  98. // At first, determine whether it is a startup section.
  99. // This is very important, as we cannot omit it.
  100. StartupNumber = GetStartupSectionNumber (CurCOFFSection->Name, sizeof (CurCOFFSection->Name));
  101. if (IsZeroI4 (CurCOFFSection->Size))
  102. {
  103. // Section is empty.
  104. // Check if the number of relocs is empty as well. If not, there
  105. // is probably an error in the object file.
  106. if (!(IsZeroI2 (CurCOFFSection->RelocCount)))
  107. Warning (FileName, "Empty section %ld has relocs.", (long) CurCOFFSectionNumber);
  108. }
  109. {
  110. I4 Flags = ReadTI4 (CurCOFFSection->Flags);
  111. // Try to allocate data for the section, if necessary.
  112. BOOLEAN HasData = (!(Flags & COFF_SECTION_BSS)) && (!IsZeroI4 (CurCOFFSection->Size)) && (!(IsZeroI4 (CurCOFFSection->PData)));
  113. SIZE Size = ReadTI4 (CurCOFFSection->Size);
  114. I1 *Data = NULL;
  115. if (HasData)
  116. {
  117. const I1 *SrcData = File + ReadTI4 (CurCOFFSection->PData);
  118. TestInFile (SrcData, I1 [Size]);
  119. TestMem ((Data = calloc (Size, 1)));
  120. memcpy (Data, SrcData, Size);
  121. }
  122. {
  123. char *SectionName = SecInfo[CurCOFFSectionNumber].Name;
  124. // Create a new section.
  125. SECTION *Section = calloc (1, sizeof (SECTION));
  126. TestMem (Section);
  127. Section->Parent = Program;
  128. // Initialize the section.
  129. Section->Data = Data;
  130. Section->Size = Size;
  131. // If neither the code flag nor the data flag is specified, default to data for non-startup sections and to code for startup sections.
  132. Section->Code = Data && ((Flags & COFF_SECTION_TEXT) || (StartupNumber && (!(Flags & COFF_SECTION_DATA))));
  133. #ifdef COFF_TIGCC_EXTENSIONS
  134. // Read TIGCC COFF section flags.
  135. Section->Mergeable = !!(Flags & COFF_SECTION_MERGEABLE);
  136. Section->Unaligned = !!(Flags & COFF_SECTION_UNALIGNED);
  137. #endif
  138. Section->Initialized = Data || InitializeBSS;
  139. Section->StartupNumber = StartupNumber;
  140. Section->Constructors = (!(strncmp (SectionName, ".ctors", 8)));
  141. Section->Destructors = (!(strncmp (SectionName, ".dtors", 8)));
  142. #ifdef DEBUGGING_INFO_SUPPORT
  143. if (!strncmp (SectionName, ".stab", 8))
  144. Section->DebuggingInfoType = DI_STAB;
  145. else if (!strncmp (SectionName, ".stabstr", 8))
  146. Section->DebuggingInfoType = DI_STABSTR;
  147. else if (!strncmp (SectionName, ".debug_a", 8))
  148. Section->DebuggingInfoType = DI_DEBUG_ABBREV;
  149. /* (This might also be .debug_aranges, we need to wait for
  150. the section symbol to disambiguate.) */
  151. else if (!strncmp (SectionName, ".debug_f", 8))
  152. Section->DebuggingInfoType = DI_DEBUG_FRAME;
  153. else if (!strncmp (SectionName, ".debug_i", 8))
  154. Section->DebuggingInfoType = DI_DEBUG_INFO;
  155. else if (!strncmp (SectionName, ".debug_l", 8))
  156. Section->DebuggingInfoType = DI_DEBUG_LINE;
  157. /* (This might also be .debug_loc, we need to wait for
  158. the section symbol to disambiguate.) */
  159. else if (!strncmp (SectionName, ".debug_m", 8))
  160. Section->DebuggingInfoType = DI_DEBUG_MACINFO;
  161. else if (!strncmp (SectionName, ".debug_p", 8))
  162. Section->DebuggingInfoType = DI_DEBUG_PUBNAMES;
  163. else if (!strncmp (SectionName, ".debug_r", 8))
  164. Section->DebuggingInfoType = DI_DEBUG_RANGES;
  165. else if (!strncmp (SectionName, ".debug_s", 8))
  166. Section->DebuggingInfoType = DI_DEBUG_STR;
  167. else if (!strncmp (SectionName, ".eh_fram", 8))
  168. Section->DebuggingInfoType = DI_EH_FRAME;
  169. #endif
  170. Section->CanCutRanges = AllRelocs;
  171. Section->FileName = FileName;
  172. // Append/insert the section.
  173. InsertSection (Program, Section);
  174. // Create a section symbol for this section.
  175. if (!(CreateSectionSymbol (Section, SectionName)))
  176. Fail ();
  177. // Put this section into the extra information table.
  178. SecInfo[CurCOFFSectionNumber].Section = Section;
  179. }
  180. // Now we are stuck: We should import the symbols all at once,
  181. // when all of the sections have been imported. We cannot import
  182. // the relocation entries now because they reference symbols. So
  183. // the only good way is to import all sections first, then import
  184. // all symbols, and then the relocs for each section.
  185. }
  186. }
  187. // *** Import Symbols ***
  188. // Create extra symbol information table.
  189. SymInfo = calloc (FileInfo.SymbolCount, sizeof (SYM_INFO));
  190. TestMem (SymInfo);
  191. // For each symbol...
  192. for (CurCOFFSymbolNumber = 0; CurCOFFSymbolNumber < FileInfo.SymbolCount; CurCOFFSymbolNumber++)
  193. {
  194. // Get pointer to this symbol.
  195. const COFF_SYMBOL *CurCOFFSymbol = &((*COFFSymbols) [CurCOFFSymbolNumber]);
  196. TestInFile (CurCOFFSymbol, COFF_SYMBOL);
  197. {
  198. // Temporary placeholder for symbol section.
  199. OFFSET SymSection = (SI2) (ReadTI2 (CurCOFFSymbol->Section));
  200. // Temporary placeholder for symbol value.
  201. OFFSET SymVal = (SI4) (ReadTI4 (CurCOFFSymbol->Value));
  202. // Temporary placeholder for symbol class.
  203. I1 SymClass = (ReadTI1 (CurCOFFSymbol->Class));
  204. // Temporary placeholder for symbol name.
  205. char SymName[MAX_SYM_LEN+1];
  206. // Set to zero for terminating zero byte.
  207. memset (SymName, 0, MAX_SYM_LEN + 1);
  208. // COFF symbol names are stored in a strange way. This is how to get them.
  209. if (IsZero (CurCOFFSymbol->Name.StringRef.Zero))
  210. {
  211. const char *Str = COFFStringTable + ReadTI4 (CurCOFFSymbol->Name.StringRef.StringOffset);
  212. TestInFile (Str, char);
  213. strncpy (SymName, Str, MAX_SYM_LEN);
  214. }
  215. else
  216. strncpy (SymName, CurCOFFSymbol->Name.Name, 8);
  217. // Handle the symbol if it is special for this linker, only proceed if not.
  218. if (!(HandleSpecialSymbol (Program, SymName)))
  219. {
  220. // Check if the section number is nonzero. If it is zero, the symbol
  221. // is somewhat special.
  222. if (SymSection)
  223. {
  224. // Check if the section number is positive and the class is
  225. // <100. If not, the symbol is very special, e.g. absolute
  226. // or debugging; so ignore it.
  227. if (SymSection > 0 && SymClass < 100)
  228. {
  229. // Check if the section number is valid.
  230. if (SymSection <= FileInfo.SectionCount)
  231. {
  232. SECTION *Section = SecInfo[SymSection-1].Section;
  233. // The symbol is a real label in a real section.
  234. if (Section)
  235. {
  236. BOOLEAN Exported = (ReadTI1 (CurCOFFSymbol->Class) == COFF_SYMBOL_EXTERNAL);
  237. OFFSET Location = SymVal - SecInfo[SymSection-1].VAddr;
  238. if ((Location == 0) && (!Exported) && (!(strncmp (SymName, SecInfo[SymSection-1].Name, COFF_SECTION_NAME_LEN))))
  239. {
  240. // Use the section symbol instead.
  241. SymInfo[CurCOFFSymbolNumber].Symbol = Section->SectionSymbol;
  242. // Rename the section symbol to the full section name as stored in the symbol.
  243. CreateSectionSymbol (Section, SymName);
  244. #ifdef DEBUGGING_INFO_SUPPORT
  245. // Disambiguate DWARF 2 section names with conflicting 8 char abbreviations.
  246. if (!strcmp (SymName, ".debug_aranges"))
  247. Section->DebuggingInfoType = DI_DEBUG_ARANGES;
  248. else if (!strcmp (SymName, ".debug_loc"))
  249. Section->DebuggingInfoType = DI_DEBUG_LOC;
  250. #endif
  251. }
  252. else
  253. {
  254. // Simply create a new symbol entry in that section.
  255. SYMBOL *Symbol = calloc (1, sizeof (SYMBOL));
  256. TestMem (Symbol);
  257. Symbol->Parent = Section;
  258. Symbol->Location = Location;
  259. strcpy (Symbol->Name, SymName);
  260. Symbol->Exported = Exported;
  261. InsertSymbol (Section, Symbol);
  262. // Put this symbol in the extra information table.
  263. SymInfo[CurCOFFSymbolNumber].Symbol = Symbol;
  264. }
  265. }
  266. else
  267. Warning (FileName, "Ignoring symbol in unimported section number %ld.", (long) SymSection);
  268. }
  269. else
  270. Warning (FileName, "Ignoring symbol in nonexisting section number %ld.", (long) SymSection);
  271. }
  272. }
  273. else
  274. {
  275. // The section number is zero. This may have two reasons:
  276. // If the value is zero as well, this is an external reference.
  277. // If the value is positive, the symbol is a common uninitialized
  278. // symbol (i.e. BSS).
  279. if (SymVal > 0)
  280. {
  281. // The symbol is a common uninitialized symbol. Make one and
  282. // put it in the extra information table.
  283. if (!((SymInfo[CurCOFFSymbolNumber].Symbol = MakeCommonSymbol (Program, SymName, SymVal, InitializeBSS, FileName))))
  284. Fail ();
  285. }
  286. // Otherwise, the symbol is an external reference or some strange
  287. // unknown thing; we cannot handle it any further here, as we
  288. // cannot assign it to a section.
  289. }
  290. }
  291. }
  292. // Skip corresponding auxiliary symbols.
  293. CurCOFFSymbolNumber += ReadTI1 (CurCOFFSymbol->AuxSymbolCount);
  294. }
  295. // *** Import Relocation Entries ***
  296. // For each section...
  297. for (CurCOFFSectionNumber = 0; CurCOFFSectionNumber < FileInfo.SectionCount; CurCOFFSectionNumber++)
  298. {
  299. const RELOC *RelocHint = NULL;
  300. // Get pointer to this section.
  301. const COFF_SECTION *CurCOFFSection = &((*COFFSections) [CurCOFFSectionNumber]);
  302. // Get pointer to section in internal data structure.
  303. SECTION *Section = SecInfo[CurCOFFSectionNumber].Section;
  304. // Only proceed if we didn't omit the section.
  305. if (Section)
  306. {
  307. COUNT RelocCount = ReadTI2 (CurCOFFSection->RelocCount);
  308. const COFF_RELOCS *CurCOFFRelocs = (const COFF_RELOCS *) (File + ReadTI4 (CurCOFFSection->PRelocs));
  309. // For each reloc...
  310. for (CurCOFFRelocNumber = 0; CurCOFFRelocNumber < RelocCount; CurCOFFRelocNumber++)
  311. {
  312. OFFSET SymNum, COFFLocation;
  313. // Get pointer to this reloc.
  314. const COFF_RELOC *CurCOFFReloc = &((*CurCOFFRelocs) [CurCOFFRelocNumber]);
  315. TestInFile (CurCOFFReloc, COFF_RELOC);
  316. // Read the location (for better error messages).
  317. COFFLocation = ReadTI4 (CurCOFFReloc->Location);
  318. // Temporary placeholder for symbol number.
  319. SymNum = ReadTI4 (CurCOFFReloc->Symbol);
  320. // Check if the symbol number is valid.
  321. if (SymNum >= 0 && SymNum < FileInfo.SymbolCount)
  322. {
  323. // Determine the reloc's size and relation.
  324. SIZE RelocSize = 0;
  325. BOOLEAN Relative = FALSE;
  326. BOOLEAN Negative = FALSE;
  327. BOOLEAN Unoptimizable = FALSE;
  328. I2 RelocType = ReadTI2 (CurCOFFReloc->Type);
  329. #ifdef COFF_TIGCC_EXTENSIONS
  330. Unoptimizable = (RelocType & COFF_RELOC_UNOPTIMIZABLE);
  331. RelocType &= ~COFF_RELOC_UNOPTIMIZABLE;
  332. #endif
  333. switch (RelocType)
  334. {
  335. case COFF_RELOC_REL1:
  336. Relative = TRUE;
  337. case COFF_RELOC_ABS1:
  338. RelocSize = 1;
  339. break;
  340. case COFF_RELOC_REL2:
  341. Relative = TRUE;
  342. case COFF_RELOC_ABS2:
  343. RelocSize = 2;
  344. break;
  345. case COFF_RELOC_REL4:
  346. Relative = TRUE;
  347. case COFF_RELOC_ABS4:
  348. RelocSize = 4;
  349. break;
  350. #ifdef COFF_TIGCC_EXTENSIONS
  351. case COFF_RELOC_ABS1_NEG:
  352. RelocSize = 1;
  353. Negative = TRUE;
  354. break;
  355. case COFF_RELOC_ABS2_NEG:
  356. RelocSize = 2;
  357. Negative = TRUE;
  358. break;
  359. #endif
  360. case COFF_RELOC_ABS4_NEG:
  361. RelocSize = 4;
  362. Negative = TRUE;
  363. break;
  364. }
  365. // Check whether we were able to translate the reloc type.
  366. if (RelocSize > 0)
  367. {
  368. OFFSET Location = COFFLocation - SecInfo[CurCOFFSectionNumber].VAddr;
  369. SYMBOL *Symbol = SymInfo[SymNum].Symbol;
  370. // Check if we really imported the target symbol.
  371. if (Symbol)
  372. {
  373. // Yes, we did.
  374. // Find the virtual address of the target section.
  375. // We will need this to subtract the virtual location of the target symbol.
  376. OFFSET VAddr = 0;
  377. OFFSET COFFSec;
  378. for (COFFSec = 0; COFFSec < FileInfo.SectionCount; COFFSec++)
  379. {
  380. if (SecInfo[COFFSec].Section == Symbol->Parent)
  381. {
  382. VAddr = SecInfo[COFFSec].VAddr;
  383. break;
  384. }
  385. }
  386. // Handle negative relocs by searching for matching positive ones.
  387. if (Negative)
  388. {
  389. // Search for a matching positive reloc.
  390. RELOC *PositiveReloc = FindMatchingReloc (Section, Location, RelocSize, FALSE, NULL, RelocHint);
  391. // We can only do something with the negative reloc
  392. // if we have found a matching positive one.
  393. if (PositiveReloc)
  394. {
  395. // Make the positive reloc relative, with
  396. // this reloc's target as the relation.
  397. LOCATION *Relation = calloc (1, sizeof (LOCATION));
  398. TestMem (Relation);
  399. Relation->Symbol = Symbol;
  400. Relation->SymbolName = Relation->Symbol->Name;
  401. PositiveReloc->Relative = TRUE;
  402. PositiveReloc->Relation = Relation;
  403. // Subtract the target offset for this reloc
  404. // from the positive reloc's fixed offset.
  405. PositiveReloc->FixedOffset += VAddr + Symbol->Location;
  406. if (RelocSize <= 1) {
  407. PositiveReloc->FixedOffset = (SI1) PositiveReloc->FixedOffset;
  408. } else if (RelocSize <= 2) {
  409. PositiveReloc->FixedOffset = (SI2) PositiveReloc->FixedOffset;
  410. }
  411. HandleLocation (PositiveReloc, Relation);
  412. RelocHint = PositiveReloc;
  413. }
  414. else
  415. Warning (FileName, "Removing negative reloc at 0x%lX in section %ld to `%s' with no matching positive reloc.", (long) Location, (long) CurCOFFSectionNumber, Symbol->Name);
  416. }
  417. else // Positive
  418. {
  419. OFFSET Offset = 0;
  420. // Now all we need to do is to set up a reloc to this symbol.
  421. RELOC *Reloc = calloc (1, sizeof (RELOC));
  422. TestMem (Reloc);
  423. Reloc->Parent = Section;
  424. Reloc->Location = Location;
  425. Reloc->Target.Symbol = Symbol;
  426. Reloc->Target.SymbolName = Reloc->Target.Symbol->Name;
  427. Reloc->Size = RelocSize;
  428. Reloc->Relative = Relative;
  429. Reloc->Unoptimizable = Unoptimizable;
  430. // Calculate the reloc's target offset.
  431. // The section contents contain the virtual
  432. // address of the target.
  433. if ((Location >= 0) && (Location + RelocSize <= Section->Size))
  434. {
  435. if (Section->Data)
  436. {
  437. Offset = ReadSTI (Section->Data + Location, RelocSize);
  438. memset (Section->Data + Location, 0, RelocSize);
  439. }
  440. else
  441. Warning (FileName, "Adding reloc %ld at 0x%lX in section %ld without data to `%s'.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, Reloc->Target.SymbolName);
  442. }
  443. else
  444. Warning (FileName, "Adding reloc %ld at 0x%lX outside of section %ld to `%s'.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, Reloc->Target.SymbolName);
  445. // Subtract the virtual address of the target symbol,
  446. // since we only want the difference to the symbol.
  447. Offset -= VAddr + Symbol->Location;
  448. // Relative relocs contain the difference between
  449. // the virtual target address and the current
  450. // virtual address. So we have to add the current
  451. // virtual address to get only the offset.
  452. if (Relative)
  453. Offset += Location + SecInfo[CurCOFFSectionNumber].VAddr;
  454. // For compatibility with files generated by
  455. // unpatched versions of GNU as, treat offsets from
  456. // section symbols as TargetOffset rather than
  457. // FixedOffset.
  458. // Apply architecture-specific fixes to the target offset.
  459. // These fixes are not needed if the correct target
  460. // symbol is referenced.
  461. if (Symbol == Symbol->Parent->SectionSymbol)
  462. Reloc->Target.Offset = ((Section->Code && Symbol->Parent->Code) ? M68kFixTargetOffset (Offset, RelocSize, Relative) : Offset);
  463. // Calculate the remaining part of the offset.
  464. Reloc->FixedOffset = Offset - Reloc->Target.Offset;
  465. if (RelocSize <= 1) {
  466. Reloc->FixedOffset = (SI1) Reloc->FixedOffset;
  467. } else if (RelocSize <= 2) {
  468. Reloc->FixedOffset = (SI2) Reloc->FixedOffset;
  469. }
  470. // Append the reloc to the linked list.
  471. InsertReloc (Section, Reloc);
  472. }
  473. }
  474. else
  475. {
  476. // No, we didn't. We have to find the cause of this.
  477. // If it is an externally defined symbol, set up a
  478. // reloc anyway. If not, give a warning.
  479. const COFF_SYMBOL *CurCOFFSymbol = &((*COFFSymbols) [SymNum]);
  480. // Check whether it is an external symbol.
  481. if (IsZeroI2 (CurCOFFSymbol->Section) && IsZeroI4 (CurCOFFSymbol->Value))
  482. {
  483. // Read the symbol name.
  484. char *SymName = calloc (MAX_SYM_LEN + 1, 1);
  485. TestMem (SymName);
  486. // COFF symbol names are stored in a strange way. This is how to get them.
  487. if (IsZero (CurCOFFSymbol->Name.StringRef.Zero))
  488. {
  489. const char *Str = COFFStringTable + ReadTI4 (CurCOFFSymbol->Name.StringRef.StringOffset);
  490. TestInFile (Str, char);
  491. strncpy (SymName, Str, MAX_SYM_LEN);
  492. }
  493. else
  494. strncpy (SymName, CurCOFFSymbol->Name.Name, 8);
  495. // Set up the reloc, without a specified symbol.
  496. // Handle negative relocs by searching for matching positive ones.
  497. if (Negative)
  498. {
  499. // Search for a matching positive reloc.
  500. RELOC *PositiveReloc = FindMatchingReloc (Section, Location, RelocSize, FALSE, NULL, RelocHint);
  501. // We can only do something with the negative reloc
  502. // if we have found a matching positive one.
  503. if (PositiveReloc)
  504. {
  505. // Make the positive reloc relative, with
  506. // this reloc's target as the relation.
  507. LOCATION *Relation = calloc (1, sizeof (LOCATION));
  508. TestMem (Relation);
  509. Relation->SymbolName = SymName;
  510. PositiveReloc->Relative = TRUE;
  511. PositiveReloc->Relation = Relation;
  512. HandleLocation (PositiveReloc, Relation);
  513. RelocHint = PositiveReloc;
  514. }
  515. else
  516. Warning (FileName, "Removing negative reloc at 0x%lX in section %ld to `%s' with no matching positive reloc.", (long) Location, (long) CurCOFFSectionNumber, SymName);
  517. }
  518. else // Positive
  519. {
  520. RELOC *Reloc = calloc (1, sizeof (RELOC));
  521. TestMem (Reloc);
  522. Reloc->Parent = Section;
  523. Reloc->Location = Location;
  524. Reloc->Target.SymbolName = SymName;
  525. Reloc->Size = RelocSize;
  526. Reloc->Relative = Relative;
  527. Reloc->Unoptimizable = Unoptimizable;
  528. // Calculate the reloc's target offset
  529. // (which is written into the fixed offset).
  530. // The section contents contain the virtual
  531. // address of the target.
  532. if (Location >= 0 && Location + RelocSize <= Section->Size)
  533. {
  534. if (Section->Data)
  535. {
  536. Reloc->FixedOffset = ReadSTI (Section->Data + Location, RelocSize);
  537. memset (Section->Data + Location, 0, RelocSize);
  538. }
  539. else
  540. Warning (FileName, "Adding reloc %ld at 0x%lX in section %ld without data to `%s'.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, Reloc->Target.SymbolName);
  541. }
  542. else
  543. Warning (FileName, "Adding reloc %ld at 0x%lX outside of section %ld to `%s'.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, Reloc->Target.SymbolName);
  544. // Relative relocs contain the difference between
  545. // the virtual target address (which is 0 or some
  546. // small offset in this case) and the current
  547. // virtual address. So we have to add the current
  548. // virtual address to get only the offset.
  549. if (Relative)
  550. Reloc->FixedOffset += Location + SecInfo[CurCOFFSectionNumber].VAddr;
  551. if (RelocSize <= 1) {
  552. Reloc->FixedOffset = (SI1) Reloc->FixedOffset;
  553. } else if (RelocSize <= 2) {
  554. Reloc->FixedOffset = (SI2) Reloc->FixedOffset;
  555. }
  556. // Add the reloc to the section.
  557. InsertReloc (Section, Reloc);
  558. }
  559. }
  560. else
  561. Warning (FileName, "Ignoring reloc %ld at 0x%lX in section %ld to unimported symbol %ld.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, (long) SymNum);
  562. }
  563. }
  564. else
  565. Warning (FileName, "Ignoring reloc %ld at 0x%lX in section %ld with unknown type `0x%lX'.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, (long) (ReadTI2 (CurCOFFReloc->Type)));
  566. }
  567. else
  568. Warning (FileName, "Ignoring reloc %ld at 0x%lX in section %ld to nonexisting symbol %ld.", (long) CurCOFFRelocNumber, (long) COFFLocation, (long) CurCOFFSectionNumber, (long) SymNum);
  569. }
  570. }
  571. }
  572. // *** Finished ***
  573. // Free allocated memory and exit with a positive result.
  574. free (SymInfo);
  575. free (SecInfo);
  576. return TRUE;
  577. #undef TestInFile
  578. #undef IsInFile
  579. #undef TestMem
  580. #undef Fail
  581. }
  582. #endif /* COFF_SUPPORT */