Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

434 lines
13 KiB

4 years ago
  1. /***********************************************************************
  2. * Microsoft (R) 32-Bit Incremental Linker
  3. *
  4. * Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
  5. *
  6. * File: i386.cpp
  7. *
  8. * File Comments:
  9. *
  10. * This module contains all i386 specific code.
  11. *
  12. ***********************************************************************/
  13. #include "link.h"
  14. VOID
  15. ApplyI386Fixups(
  16. PCON pcon,
  17. PIMAGE_RELOCATION prel,
  18. DWORD creloc,
  19. BYTE *pbRawData,
  20. PIMAGE_SYMBOL rgsym,
  21. PIMAGE pimage,
  22. PSYMBOL_INFO rgsymInfo)
  23. /*++
  24. Routine Description:
  25. Applys all I386 fixups to raw data.
  26. Arguments:
  27. pcon - contribution
  28. pbRawData - raw data to apply fixups to
  29. Return Value:
  30. None.
  31. --*/
  32. {
  33. BOOL fVxD;
  34. BOOL fFixed;
  35. BOOL fDebugFixup;
  36. DWORD rvaSec;
  37. DWORD iReloc;
  38. fVxD = pimage->imaget == imagetVXD;
  39. fFixed = pimage->Switch.Link.fFixed;
  40. fDebugFixup = (PsecPCON(pcon) == psecDebug);
  41. BOOL fSaveDebugFixup = (pimage->Switch.Link.DebugType & FixupDebug) && !fDebugFixup;
  42. rvaSec = pcon->rva;
  43. for (iReloc = creloc; iReloc; iReloc--, prel++) {
  44. DWORD rvaCur;
  45. BYTE *pb;
  46. DWORD isym;
  47. SHORT isecTarget;
  48. DWORD rvaTarget;
  49. DWORD vaTarget;
  50. BOOL fAbsolute;
  51. rvaCur = rvaSec + prel->VirtualAddress - RvaSrcPCON(pcon);
  52. pb = pbRawData + prel->VirtualAddress - RvaSrcPCON(pcon);
  53. isym = prel->SymbolTableIndex;
  54. isecTarget = rgsym[isym].SectionNumber;
  55. rvaTarget = rgsym[isym].Value;
  56. if (fINCR && !fDebugFixup && rgsymInfo[isym].fJmpTbl &&
  57. (rgsym[isym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
  58. rgsym[isym].StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
  59. rgsym[isym].StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL)) {
  60. if (*(DWORD UNALIGNED *) pb) {
  61. // Don't go thru the jump table for fixups to functions on non-zero offset
  62. MarkExtern_FuncFixup(&rgsym[isym], pimage, pcon);
  63. } else {
  64. // -1 since offset is to the addr
  65. rvaTarget = pconJmpTbl->rva + rgsymInfo[isym].Offset - 1;
  66. }
  67. }
  68. if (isecTarget == IMAGE_SYM_ABSOLUTE) {
  69. fAbsolute = TRUE;
  70. vaTarget = rvaTarget;
  71. } else {
  72. fAbsolute = FALSE;
  73. vaTarget = pimage->ImgOptHdr.ImageBase + rvaTarget;
  74. // UNDONE: Check for rvaTarget == 0. Possible fixup to discarded code?
  75. }
  76. if (fSaveDebugFixup && !fAbsolute) {
  77. SaveDebugFixup(prel->Type, 0, rvaCur, rvaTarget);
  78. }
  79. switch (prel->Type) {
  80. DWORD ibCur;
  81. DWORD ib;
  82. DWORD baseRelocVA;
  83. DWORD baseRelocValue;
  84. PSEC psec;
  85. case IMAGE_REL_I386_REL32:
  86. if (pimage->Switch.Link.fMap) {
  87. SaveFixupForMapFile(rvaCur);
  88. }
  89. if (fVxD) {
  90. // Calculate the source and destination addresses for VxDs
  91. ibCur = rvaCur - PsecPCON(pcon)->rva;
  92. psec = PsecFindIsec(isecTarget, &pimage->secs);
  93. assert(psec != NULL);
  94. assert(psec->isec);
  95. ib = rvaTarget - psec->rva;
  96. if (PsecPCON(pcon) != psec) {
  97. // Only store base reloc for inter-section references
  98. baseRelocVA = VXD_PACK_VA(PsecPCON(pcon), ibCur);
  99. baseRelocValue = VXD_PACK_VA(psec, ib);
  100. // Check to see if we are losing info when we squish offset into 24 bits
  101. struct _OFF { signed long off:24; } OFF;
  102. DWORD ibTemp = OFF.off = VXD_UNPACK_OFFSET(baseRelocValue);
  103. if (ibTemp != ib) {
  104. FatalPcon(pcon, VXDFIXUPOVERFLOW, SzNameFixupSym(pimage, rgsym + isym));
  105. }
  106. StoreBaseRelocation(IMAGE_REL_BASED_VXD_RELATIVE,
  107. baseRelocVA,
  108. isecTarget,
  109. baseRelocValue,
  110. fFixed);
  111. break;
  112. }
  113. // Compute the RVA to add in to the fixup destination ... it
  114. // is the section-relative offset of the target minus the
  115. // section-relative offset of the next instruction.
  116. rvaTarget = ib - (ibCur + sizeof(DWORD));
  117. } else {
  118. // The displacement is the RVA of the target
  119. // minus the RVA of the next instruction.
  120. rvaTarget -= rvaCur + sizeof(DWORD);
  121. if (!fAbsolute && pimage->Switch.Link.fNewRelocs) {
  122. if (isecTarget != PsecPCON(pcon)->isec) {
  123. StoreBaseRelocation(IMAGE_REL_BASED_REL32,
  124. rvaCur,
  125. isecTarget,
  126. 0,
  127. fFixed);
  128. }
  129. }
  130. }
  131. *(DWORD UNALIGNED *) pb += rvaTarget;
  132. break;
  133. case IMAGE_REL_I386_DIR32:
  134. if (fDebugFixup) {
  135. // When a DIR32 fixup is found in a debug section, it is
  136. // treated as a SECREL fixup followed by a SECTION fixup.
  137. if (fAbsolute) {
  138. // Max section # + 1 is the sstSegMap entry for absolute
  139. // symbols.
  140. *(WORD UNALIGNED *) (pb + sizeof(DWORD)) += (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
  141. } else {
  142. psec = PsecFindIsec(isecTarget, &pimage->secs);
  143. if (psec != NULL) {
  144. rvaTarget -= psec->rva;
  145. *(WORD UNALIGNED *) (pb + sizeof(DWORD)) += psec->isec;
  146. } else {
  147. // This occurs when a discarded comdat is the target of
  148. // a relocation in the .debug section.
  149. assert(rvaTarget == 0);
  150. }
  151. }
  152. *(DWORD UNALIGNED *) pb += rvaTarget;
  153. break;
  154. }
  155. if (fVxD && !fAbsolute) {
  156. ibCur = rvaCur - PsecPCON(pcon)->rva;
  157. psec = PsecFindIsec(isecTarget, &pimage->secs);
  158. assert(psec != NULL);
  159. assert(psec->isec);
  160. ib = rvaTarget - psec->rva;
  161. // VXD relocations are not additive. Add in
  162. // the displacement present in the object file.
  163. ib += *(DWORD UNALIGNED *) pb;
  164. baseRelocVA = VXD_PACK_VA(PsecPCON(pcon), ibCur);
  165. baseRelocValue = VXD_PACK_VA(psec, ib);
  166. // Check to see if we are losing info when we squish offset into 24 bits
  167. struct _OFF { signed long off:24; } OFF;
  168. DWORD ibTemp = OFF.off = VXD_UNPACK_OFFSET(baseRelocValue);
  169. if (ibTemp != ib) {
  170. FatalPcon(pcon, VXDFIXUPOVERFLOW, SzNameFixupSym(pimage, rgsym + isym));
  171. }
  172. StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
  173. baseRelocVA,
  174. isecTarget,
  175. baseRelocValue,
  176. fFixed);
  177. break;
  178. }
  179. *(DWORD UNALIGNED *) pb += vaTarget;
  180. if (!fAbsolute) {
  181. StoreBaseRelocation(IMAGE_REL_BASED_HIGHLOW,
  182. rvaCur,
  183. isecTarget,
  184. 0,
  185. fFixed);
  186. }
  187. break;
  188. case IMAGE_REL_I386_DIR32NB:
  189. *(DWORD UNALIGNED *) pb += rvaTarget;
  190. break;
  191. case IMAGE_REL_I386_SECREL:
  192. if (!fAbsolute) {
  193. psec = PsecFindIsec(isecTarget, &pimage->secs);
  194. if (psec != NULL) {
  195. rvaTarget -= psec->rva;
  196. } else {
  197. // This occurs when a discarded comdat is the target of
  198. // a relocation in the .debug section.
  199. assert(rvaTarget == 0);
  200. }
  201. }
  202. *(DWORD UNALIGNED *) pb += rvaTarget;
  203. break;
  204. case IMAGE_REL_I386_SECTION:
  205. if (isecTarget > 0) {
  206. *(WORD UNALIGNED *) pb += (WORD) isecTarget;
  207. } else if (fAbsolute) {
  208. // Max section # + 1 is the sstSegMap entry for absolute
  209. // symbols.
  210. *(WORD UNALIGNED *) pb += (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
  211. } else {
  212. *(WORD UNALIGNED *) pb += 0;
  213. }
  214. break;
  215. case IMAGE_REL_I386_ABSOLUTE:
  216. // Ignore (fixup not required).
  217. break;
  218. case IMAGE_REL_I386_SEG12:
  219. WarningPcon(pcon, UNKNOWN_SEG12_FIXUP, prel->VirtualAddress);
  220. break;
  221. case IMAGE_REL_I386_DIR16:
  222. if (fVxD) {
  223. psec = PsecFindIsec(isecTarget, &pimage->secs);
  224. if (psec != NULL) {
  225. rvaTarget -= psec->rva;
  226. } else {
  227. // UNDONE: Is this possible for VxDs?
  228. // This occurs when a discarded comdat is the target of
  229. // a relocation in the .debug section.
  230. assert(rvaTarget == 0);
  231. }
  232. *(SHORT UNALIGNED *) pb += (SHORT) rvaTarget;
  233. break;
  234. }
  235. // Fall through for non-VxDs
  236. case IMAGE_REL_I386_REL16:
  237. if (fVxD) {
  238. // The source and target must be in the same section
  239. if (PsecPCON(pcon)->isec != isecTarget) {
  240. // UNDONE: This should be an error
  241. assert(FALSE);
  242. }
  243. rvaTarget -= rvaCur + sizeof(WORD);
  244. *(SHORT UNALIGNED *) pb += (SHORT) rvaTarget;
  245. break;
  246. }
  247. // Fall through for non-VxDs
  248. default:
  249. ErrorPcon(pcon, UNKNOWNFIXUP, prel->Type, SzNameFixupSym(pimage, rgsym + isym));
  250. CountFixupError(pimage);
  251. break;
  252. }
  253. }
  254. }
  255. VOID I386LinkerInit(PIMAGE pimage, BOOL *pfIlinkSupported)
  256. {
  257. // If section alignment switch not used, set the default.
  258. if (!FUsedOpt(pimage->SwitchInfo, OP_ALIGN) && pimage->imaget != imagetVXD) {
  259. pimage->ImgOptHdr.SectionAlignment = _4K;
  260. }
  261. if (FUsedOpt(pimage->SwitchInfo, OP_GPSIZE)) {
  262. Warning(NULL, SWITCH_INCOMPATIBLE_WITH_MACHINE, "GPSIZE", "IX86");
  263. pimage->Switch.Link.GpSize = 0;
  264. }
  265. *pfIlinkSupported = TRUE;
  266. ApplyFixups = ApplyI386Fixups;
  267. // If the section alignment is < _4K then make the file alignment the
  268. // same as the section alignment. This ensures that the image will
  269. // be the same in memory as in the image file, since the alignment is less
  270. // than the maximum alignment of memory-mapped files.
  271. if (pimage->ImgOptHdr.SectionAlignment < _4K) {
  272. fImageMappedAsFile = TRUE;
  273. pimage->ImgOptHdr.FileAlignment = pimage->ImgOptHdr.SectionAlignment;
  274. }
  275. }
  276. const char *SzI386RelocationType(WORD wType, WORD *pcb, BOOL *pfSymValid)
  277. {
  278. const char *szName;
  279. WORD cb;
  280. switch (wType) {
  281. case IMAGE_REL_I386_ABSOLUTE:
  282. szName = "ABS";
  283. cb = 0;
  284. break;
  285. case IMAGE_REL_I386_DIR16:
  286. szName = "DIR16";
  287. cb = sizeof(WORD);
  288. break;
  289. case IMAGE_REL_I386_REL16:
  290. szName = "REL16";
  291. cb = sizeof(WORD);
  292. break;
  293. case IMAGE_REL_I386_DIR32:
  294. szName = "DIR32";
  295. cb = sizeof(DWORD);
  296. break;
  297. case IMAGE_REL_I386_DIR32NB:
  298. szName = "DIR32NB";
  299. cb = sizeof(DWORD);
  300. break;
  301. case IMAGE_REL_I386_SEG12:
  302. szName = "SEG12";
  303. cb = sizeof(WORD);
  304. break;
  305. case IMAGE_REL_I386_REL32:
  306. szName = "REL32";
  307. cb = sizeof(DWORD);
  308. break;
  309. case IMAGE_REL_I386_SECTION:
  310. szName = "SECTION";
  311. cb = sizeof(WORD);
  312. break;
  313. case IMAGE_REL_I386_SECREL:
  314. szName = "SECREL";
  315. cb = sizeof(DWORD);
  316. break;
  317. default:
  318. szName = NULL;
  319. cb = 0;
  320. break;
  321. }
  322. *pcb = cb;
  323. *pfSymValid = (cb != 0);
  324. return(szName);
  325. }