Ping on this one.
Short version: in a 16-bit code segment, a near CALL or JMP rel16 that only
reaches its target by wrapping EIP through 0xFFFF runs with EIP left
untruncated. The SDM has the 16-bit form truncate EIP to 16 bits, so in my
test the branch should land at CS:0x0020, and instead execution carries on at
EIP 0x10020.
It's fiddly to hit. You need all four of these at once:
- a 16-bit code segment, D/B clear, so it really is a rel16 and EIP really
is masked to 16 bits
- a cs_base that isn't page aligned. If it is aligned, the wrap always
crosses a page boundary in the linear address too, and the existing
same-page test happens to give the right answer
- the untruncated linear target landing in the same guest page as the start
of the TB, which is what makes gen_jmp_rel() skip the masking
- a CF_PCREL translation. It goes away under -d nochain and under
-accel tcg,one-insn-per-tb=on, both of which set CF_NO_GOTO_TB and force
the masking back on
One thing I got wrong in v1: it dropped the data16-in-code32 guard on the
assumption that the new condition subsumed it. It doesn't. That guard is
there for a different case, EIP starting out above the mask, so v1 would have
swapped one problem for another. v2 does something narrower and leaves the
guard where it is.
The test is the same test with the same geometry, just split out into its own
patch and wired into tests/tcg/i386/system/meson.build now that the tcg tests
meson rework has landed.
I'll send v2 as a new thread shortly and link it back here.
Paul