diff options
| author | Philip <pipcet@gmail.com> | 2015-04-23 18:08:28 +0000 |
|---|---|---|
| committer | Philip <pipcet@gmail.com> | 2015-04-23 18:08:28 +0000 |
| commit | 059aea5d35dd2a132b4c0016c7ceddbfa5bb9104 (patch) | |
| tree | 8c8839a44186c440b8014888cdae3e12932d25b8 /win32/include/sec_api/stdio_s.h | |
| parent | aacf65bbfa1dad801428c1978cebb45400a2bd93 (diff) | |
| download | tinycc-059aea5d35dd2a132b4c0016c7ceddbfa5bb9104.tar.gz tinycc-059aea5d35dd2a132b4c0016c7ceddbfa5bb9104.tar.bz2 | |
fix a subtle x86-64 calling bug
I ran into an issue playing with tinycc, and tracked it down to a rather
weird assumption in the function calling code. This breaks only when
varargs and float/double arguments are combined, I think, and only when
calling GCC-generated (or non-TinyCC, at least) code. The problem is we
sometimes generate code like this:
804a468: 4c 89 d9 mov %r11,%rcx
804a46b: b8 01 00 00 00 mov $0x1,%eax
804a470: 48 8b 45 c0 mov -0x40(%rbp),%rax
804a474: 4c 8b 18 mov (%rax),%r11
804a477: 41 ff d3 callq *%r11
for a function call. Note how $eax is first set to the correct value,
then clobbered when we try to load the function pointer into R11. With
the patch, the code generated is:
804a468: 4c 89 d9 mov %r11,%rcx
804a46b: b8 01 00 00 00 mov $0x1,%eax
804a470: 4c 8b 5d c0 mov -0x40(%rbp),%r11
804a474: 4d 8b 1b mov (%r11),%r11
804a477: 41 ff d3 callq *%r11
which is correct.
This becomes an issue when get_reg(RC_INT) is modified not always to
return %rax after a save_regs(0), because then another register (%ecx,
say) is clobbered, and the function passed an invalid argument.
A rather convoluted test case that generates the above code is
included. Please note that the test will not cause a failure because
TinyCC code ignores the %rax argument, but it will cause incorrect
behavior when combined with GCC code, which might wrongly fail to save
XMM registers and cause data corruption.
Diffstat (limited to 'win32/include/sec_api/stdio_s.h')
0 files changed, 0 insertions, 0 deletions
