/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA, int filePosWhenPlaced) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: case RelocType.IMAGE_REL_SYMBOL_SIZE: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32_PCREL: { relocationLength = 8; const uint offsetCorrection = 12; delta = unchecked (targetRVA - (sourceRVA + offsetCorrection)); break; } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: { relocationLength = 4; int sourcePageRVA = sourceRVA & ~0xfff; // Page delta always fits in 21 bits as long as we use 4-byte RVAs delta = ((targetRVA - sourcePageRVA) >> 12) & 0x1f_ffff; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A: { relocationLength = 4; delta = targetRVA & 0xfff; break; } case RelocType.IMAGE_REL_FILE_ABSOLUTE: { relocationLength = 4; delta = filePosWhenPlaced; break; } case RelocType.IMAGE_REL_BASED_LOONGARCH64_PC: case RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR: { relocationLength = 8; delta = targetRVA - sourceRVA; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); // Supporting non-zero values for ARM64 would require refactoring this function if (((relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21) || (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_PC) || (relocationType == RelocType.IMAGE_REL_BASED_LOONGARCH64_JIR) ) && (value != 0)) { throw new NotSupportedException(); } Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }
/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: case RelocType.IMAGE_REL_SYMBOL_SIZE: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21: { relocationLength = 4; delta = (targetRVA - sourceRVA) >> 12; break; } case RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A: { relocationLength = 4; delta = targetRVA & 0xfff; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); // Supporting non-zero values for ARM64 would require refactoring this function if (((relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEBASE_REL21) || (relocationType == RelocType.IMAGE_REL_BASED_ARM64_PAGEOFFSET_12A)) && (value != 0)) { throw new NotSupportedException(); } Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }
/// <summary> /// Process a single relocation by copying the required number of bytes into a /// buffer, applying the relocation and writing it to the output file. /// </summary> /// <param name="relocationType">Relocation type to process</param> /// <param name="sourceRVA">RVA representing the address to relocate</param> /// <param name="targetRVA">RVA representing the relocation target</param> public void ProcessRelocation(RelocType relocationType, int sourceRVA, int targetRVA) { int relocationLength = 0; long delta = 0; switch (relocationType) { case RelocType.IMAGE_REL_BASED_ABSOLUTE: // No relocation return; case RelocType.IMAGE_REL_BASED_HIGHLOW: { relocationLength = 4; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_ADDR32NB: { relocationLength = 4; delta = targetRVA; break; } case RelocType.IMAGE_REL_BASED_REL32: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } case RelocType.IMAGE_REL_BASED_DIR64: { relocationLength = 8; delta = unchecked (targetRVA + (long)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_MOV32: { relocationLength = 8; delta = unchecked (targetRVA + (int)_defaultImageBase); break; } case RelocType.IMAGE_REL_BASED_THUMB_BRANCH24: { relocationLength = 4; delta = targetRVA - sourceRVA - 4; break; } default: throw new NotSupportedException(); } if (relocationLength > 0) { CopyBytesToBuffer(_relocationBuffer, relocationLength); unsafe { fixed(byte *bufferContent = _relocationBuffer) { long value = Relocation.ReadValue(relocationType, bufferContent); Relocation.WriteValue(relocationType, bufferContent, unchecked (value + delta)); } } // Write the relocated bytes to the output file _outputStream.Write(_relocationBuffer, 0, relocationLength); _outputFilePos += relocationLength; } }