Skip to content

x86: keep all bits in bextr when the length covers the operand - #2453

Open
bacescuandrei wants to merge 1 commit into
unicorn-engine:devfrom
bacescuandrei:fix/bextr-length
Open

bacescuandrei wants to merge 1 commit into
unicorn-engine:devfrom
bacescuandrei:fix/bextr-length

Conversation

@bacescuandrei

Copy link
Copy Markdown

bextr clamps LEN to the operand-size bound (63 or 31) and builds the mask as (1 << LEN) - 1, so a length at or above the operand size drops the top bit of the result:

bextr rax, rbx, rcx   rbx = 0x8000000000000000, rcx = 0x4000 (start 0, len 64)
  unicorn: rax = 0                  hardware / SDM: rax = 0x8000000000000000
bextr eax, ebx, ecx   ebx = 0x80000000, ecx = 0x2000 (start 0, len 32)
  unicorn: eax = 0                  hardware / SDM: eax = 0x80000000

The Intel SDM defines the result as the LEN bits starting at START, with all remaining bits of the operand kept when LEN reaches past it. This change builds an inverse mask -1 << LEN that is cleared for lengths above the bound, which is how QEMU's current gen_BEXTR (target/i386/tcg/emit.c.inc) does it. Lengths below the operand size are unchanged.

Test: test_x86_bextr_len in tests/unit/test_x86.c covers lengths 64 and 255, length 63, start 63 with length 1, and the 32-bit form with length 32. Without the change the length-64, length-255 and 32-bit cases fail; with it the test and the rest of test_x86 pass (x86-only Debug build, Linux x86_64).

bextr clamped LEN to 63 (or 31) and built the mask as (1 << LEN) - 1,
so a length at or above the operand size dropped the top bit: bextr
rax, rbx, rcx with rbx = 0x8000000000000000 and rcx = 0x4000 gave 0.
Build an inverse mask that is cleared for lengths above the bound, as
QEMU gen_BEXTR does.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant