- abs_offset = le32_to_cpu(*(int32_t*)(uncompressed_data + i + 1));
-
- if (abs_offset >= -i && abs_offset < file_size) {
- if (abs_offset >= 0) {
- /* "good translation" */
- rel_offset = abs_offset - i;
- } else {
- /* "compensating translation" */
- rel_offset = abs_offset + file_size;
- }
- *(int32_t*)(uncompressed_data + i + 1) =
- cpu_to_le32(rel_offset);
+ *call_insn_target = cpu_to_le32(rel_offset);
+ }
+}
+
+/* Undo the 'E8' preprocessing, where the targets of x86 CALL instructions were
+ * changed from relative offsets to absolute offsets.
+ *
+ * Note that this call instruction preprocessing can and will be used on any
+ * data even if it is not actually x86 machine code. In fact, this type of
+ * preprocessing appears to always be used in LZX-compressed resources in WIM
+ * files; there is no bit to indicate whether it is used or not, unlike in the
+ * LZX compressed format as used in cabinet files, where a bit is reserved for
+ * that purpose.
+ *
+ * Call instruction preprocessing is disabled in the last 6 bytes of the
+ * uncompressed data, which really means the 5-byte call instruction cannot
+ * start in the last 10 bytes of the uncompressed data. This is one of the
+ * errors in the LZX documentation.
+ *
+ * Call instruction preprocessing does not appear to be disabled after the
+ * 32768th chunk of a WIM stream, which is apparently is yet another difference
+ * from the LZX compression used in cabinet files.
+ *
+ * Call instruction processing is supposed to take the file size as a parameter,
+ * as it is used in calculating the translated jump targets. But in WIM files,
+ * this file size is always the same (LZX_WIM_MAGIC_FILESIZE == 12000000).*/
+static void undo_call_insn_preprocessing(u8 uncompressed_data[],
+ int uncompressed_data_len)
+{
+ for (int i = 0; i < uncompressed_data_len - 10; i++) {
+ if (uncompressed_data[i] == 0xe8) {
+ undo_call_insn_translation((u32*)&uncompressed_data[i + 1],
+ i,
+ LZX_WIM_MAGIC_FILESIZE);
+ i += 4;