Hi,
recently i came across a situation were on linux-i386 not only %eax was
altered after a syscall but also %ebx. I tracked this problem down, to
gcc re-using a variable passed to a function.
This was found on a debian system with a 2.4.17 kernel compiled with gcc
2.95.2 and verified on another system, kernel 2.4.18 compiled with 2.95.4
Attached is small program to test for this 'bug'
a syscall gets his data off the stack, the stack looks like:
saved(edx)
saved(ecx)
saved(ebx)
return_addres (somewhere in entry.S)
When the syscall is called.
the register came there through use of 'SAVE_ALL'.
After the syscall returns these registers are restored using RESTORE_ALL
and execution is transferred to userland again.
A short snippet of sys_poll, with irrelavant data removed.
sys_poll(struct pollfd *ufds, .. , ..) {
...
ufds++;
...
}
It seems that gcc in certain cases optimizes in such a way that it changes
the variable ufds as placed on the stack directly. Which results in saved(ebx)
being overwritten and thus in a changed %ebx on return from the system call.
I don't know if this is considered a bug, and if it is, from whom.
If it's not a bug it means low-level userland programs need to be rewritten
to store all registers on a syscall and restore them on return.
It shouldn't be a bug in gcc, since the C-standard doesn't talk about how to
pass variables and stuff. So it seems like a kernel(-gcc-interaction) bug.
To solve this issue 2 solutions spring to mind
1) add a flag to gcc to tell it that it shouldn't do this optimization, this
won't work with the gcc's already out there.
2) When calling a syscall explicitly push all variable an extra time, since
the code in entry.S doesn't know the amount of variables to a syscall it
needs to push all theoretical 6 parameters every time, a not so nice
overhead.
I hope someone can shed some light on this issue, i am not myself reading
the linux-kernel mailing list, and would like to be cc'd if possible (i'll
also check the archives so it's not 100% needed).
Thanks in advance,
Dvorak
--5mCyUwZo2JvN/JJP
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="reg-bug.c"
/*
* usage is easy, though not very friendly:
* gcc reg-bug.c
* ./a.out | od -tx4
* <ENTER>
* if the values outputted by hexdump are different the 'bug' is present
* else the bug is not present
* on a system without the bug:
dvorak$ dmesg | head -1
Linux version 2.2.21 (kernel@debian) (gcc version 2.95.4 20011002 (Debian prerelease)) #6 Sat Sep 7 22:48:42 CEST 2002
dvorak$ gcc reg-bug.c
dvorak$ ./a.out | od -tx4
0000000 bff7de6c bff7de6c
* on a 'buggy' system:
*
(m4xx) dmesg | head -1
(m4xx) Linux version 2.4.18 (maxx@meuuh) (gcc version 2.95.4 20011002 (Debian
+prerelease)) #2 Mon Jul 29 17:01:30 CEST 2002
(m4xx) $ gcc reg-bug.c
(m4xx) $ ./a.out | od -tx4
(m4xx) 0000000 bffffdcc bffffdbc
*/
int main(void)
{
__asm__("
pushl $0x00010001
pushl $0x0
pushl $0x00010001
pushl $0x1
movl %esp, %ebx
pushl %ebx
movl $0x2, %ecx
movl $0xa8, %eax
movl $(-1), %edx
int $0x80
pushl %ebx
movl %esp, %ecx
movl $0x08, %edx
movl $0x04, %eax
movl $0x01, %ebx
int $0x80
movl $0x01, %eax
xorl %ebx, %ebx
int $0x80
");
}
--5mCyUwZo2JvN/JJP--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/