diff --git a/mozglue/linker/Makefile.in b/mozglue/linker/Makefile.in index d6b3ae2c5d8..1bc914cb3f0 100644 --- a/mozglue/linker/Makefile.in +++ b/mozglue/linker/Makefile.in @@ -43,3 +43,6 @@ else HOST_CXXFLAGS += -DTARGET_ARM endif endif +ifeq (x86,$(CPU_ARCH)) +HOST_CXXFLAGS += -DTARGET_X86 +endif diff --git a/mozglue/linker/SeekableZStream.cpp b/mozglue/linker/SeekableZStream.cpp index a8e2856b2d1..a2a4513bc36 100644 --- a/mozglue/linker/SeekableZStream.cpp +++ b/mozglue/linker/SeekableZStream.cpp @@ -170,6 +170,88 @@ BCJ_ARM_filter(off_t offset, SeekableZStream::FilterDirection dir, } } +/* Branch/Call/Jump conversion filter for x86, derived from xz-utils + * by Igor Pavlov and Lasse Collin, published in the public domain */ + +#define Test86MSByte(b) ((b) == 0 || (b) == 0xff) + +static void +BCJ_X86_filter(off_t offset, SeekableZStream::FilterDirection dir, + unsigned char *buf, size_t size) +{ + static const bool MASK_TO_ALLOWED_STATUS[8] = + { true, true, true, false, true, false, false, false }; + + static const uint32_t MASK_TO_BIT_NUMBER[8] = + { 0, 1, 2, 2, 3, 3, 3, 3 }; + + uint32_t prev_mask = 0; + uint32_t prev_pos = 0; + + for (size_t i = 0; i <= size - 5;) { + uint8_t b = buf[i]; + if (b != 0xe8 && b != 0xe9) { + ++i; + continue; + } + + const uint32_t off = offset + (uint32_t)(i) - prev_pos; + prev_pos = offset + (uint32_t)(i); + + if (off > 5) { + prev_mask = 0; + } else { + for (uint32_t i = 0; i < off; ++i) { + prev_mask &= 0x77; + prev_mask <<= 1; + } + } + + b = buf[i + 4]; + + if (Test86MSByte(b) && MASK_TO_ALLOWED_STATUS[(prev_mask >> 1) & 0x7] + && (prev_mask >> 1) < 0x10) { + + uint32_t src = ((uint32_t)(b) << 24) + | ((uint32_t)(buf[i + 3]) << 16) + | ((uint32_t)(buf[i + 2]) << 8) + | (buf[i + 1]); + + uint32_t dest; + while (true) { + if (dir == SeekableZStream::FILTER) + dest = src + (offset + (uint32_t)(i) + 5); + else + dest = src - (offset + (uint32_t)(i) + 5); + + if (prev_mask == 0) + break; + + const uint32_t i = MASK_TO_BIT_NUMBER[prev_mask >> 1]; + + b = (uint8_t)(dest >> (24 - i * 8)); + + if (!Test86MSByte(b)) + break; + + src = dest ^ ((1 << (32 - i * 8)) - 1); + } + + buf[i + 4] = (uint8_t)(~(((dest >> 24) & 1) - 1)); + buf[i + 3] = (uint8_t)(dest >> 16); + buf[i + 2] = (uint8_t)(dest >> 8); + buf[i + 1] = (uint8_t)(dest); + i += 5; + prev_mask = 0; + + } else { + ++i; + prev_mask |= 1; + if (Test86MSByte(b)) + prev_mask |= 0x10; + } + } +} SeekableZStream::ZStreamFilter SeekableZStream::GetFilter(SeekableZStream::FilterId id) @@ -179,6 +261,8 @@ SeekableZStream::GetFilter(SeekableZStream::FilterId id) return BCJ_Thumb_filter; case BCJ_ARM: return BCJ_ARM_filter; + case BCJ_X86: + return BCJ_X86_filter; default: return NULL; } diff --git a/mozglue/linker/SeekableZStream.h b/mozglue/linker/SeekableZStream.h index be2f4cacdb2..018b9347dd6 100644 --- a/mozglue/linker/SeekableZStream.h +++ b/mozglue/linker/SeekableZStream.h @@ -106,6 +106,7 @@ public: NONE, BCJ_THUMB, BCJ_ARM, + BCJ_X86, FILTER_MAX }; static ZStreamFilter GetFilter(FilterId id); diff --git a/mozglue/linker/szip.cpp b/mozglue/linker/szip.cpp index 586c53dcfbe..5711ffeffc0 100644 --- a/mozglue/linker/szip.cpp +++ b/mozglue/linker/szip.cpp @@ -144,6 +144,8 @@ private: SeekableZStream::BCJ_THUMB; #elif defined(TARGET_ARM) SeekableZStream::BCJ_ARM; +#elif defined(TARGET_X86) + SeekableZStream::BCJ_X86; #else SeekableZStream::NONE; #endif @@ -352,6 +354,8 @@ int main(int argc, char* argv[]) filter = SeekableZStream::BCJ_ARM; else if (strcmp(firstArg[0], "thumb") == 0) filter = SeekableZStream::BCJ_THUMB; + else if (strcmp(firstArg[0], "x86") == 0) + filter = SeekableZStream::BCJ_X86; else { log("Invalid filter"); return 1;