4 * Code shared between the compressor and decompressor for the LZMS compression
9 * Copyright (C) 2013 Eric Biggers
11 * This file is part of wimlib, a library for working with WIM files.
13 * wimlib is free software; you can redistribute it and/or modify it under the
14 * terms of the GNU General Public License as published by the Free
15 * Software Foundation; either version 3 of the License, or (at your option)
18 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
19 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20 * A PARTICULAR PURPOSE. See the GNU General Public License for more
23 * You should have received a copy of the GNU General Public License
24 * along with wimlib; if not, see http://www.gnu.org/licenses/.
31 #include "wimlib/lzms.h"
32 #include "wimlib/endianness.h"
35 lzms_maybe_do_x86_translation(u8 data[], s32 i, s32 num_op_bytes,
36 s32 *closest_target_usage_p,
37 s32 last_target_usages[], s32 max_trans_offset,
43 if (i - *closest_target_usage_p <= max_trans_offset) {
44 LZMS_DEBUG("Undid x86 translation at position %d "
45 "(opcode 0x%02x)", i, data[i]);
46 le32 *p32 = (le32*)&data[i + num_op_bytes];
47 u32 n = le32_to_cpu(*p32);
48 *p32 = cpu_to_le32(n - i);
50 pos = i + le16_to_cpu(*(const le16*)&data[i + num_op_bytes]);
52 pos = i + le16_to_cpu(*(const le16*)&data[i + num_op_bytes]);
54 if (i - *closest_target_usage_p <= max_trans_offset) {
55 LZMS_DEBUG("Did x86 translation at position %d "
56 "(opcode 0x%02x)", i, data[i]);
57 le32 *p32 = (le32*)&data[i + num_op_bytes];
58 u32 n = le32_to_cpu(*p32);
59 *p32 = cpu_to_le32(n + i);
63 i += num_op_bytes + sizeof(le32) - 1;
65 if (i - last_target_usages[pos] <= LZMS_X86_MAX_GOOD_TARGET_OFFSET)
66 *closest_target_usage_p = i;
68 last_target_usages[pos] = i;
74 lzms_may_x86_translate(const u8 p[], s32 *max_offset_ret)
76 /* Switch on first byte of the opcode, assuming it is really an x86
78 *max_offset_ret = LZMS_X86_MAX_TRANSLATION_OFFSET;
82 if (p[2] == 0x5 || p[2] == 0xd) {
83 /* Load relative (x86_64) */
86 } else if (p[1] == 0x8d) {
87 if ((p[2] & 0x7) == 0x5) {
88 /* Load effective address relative (x86_64) */
96 if ((p[2] & 0x7) == 0x5) {
97 /* Load effective address relative (x86_64) */
105 *max_offset_ret = LZMS_X86_MAX_TRANSLATION_OFFSET / 2;
114 if (p[1] == 0x83 && p[2] == 0x05) {
115 /* Lock add relative */
132 * Translate relative addresses embedded in x86 instructions into absolute
133 * addresses (@undo == %false), or undo this translation (@undo == %true).
135 * @last_target_usages is a temporary array of length >= 65536.
138 lzms_x86_filter(u8 data[], s32 size, s32 last_target_usages[], bool undo)
140 s32 closest_target_usage = -LZMS_X86_MAX_TRANSLATION_OFFSET - 1;
142 for (s32 i = 0; i < 65536; i++)
143 last_target_usages[i] = -LZMS_X86_MAX_GOOD_TARGET_OFFSET - 1;
145 for (s32 i = 0; i < size - 11; ) {
146 s32 max_trans_offset;
149 n = lzms_may_x86_translate(data + i, &max_trans_offset);
150 if (max_trans_offset) {
151 i = lzms_maybe_do_x86_translation(data, i, n,
152 &closest_target_usage,