linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: Syscall changes registers beyond %eax, on linux-i386
@ 2002-09-19 17:44 Petr Vandrovec
  2002-09-19 18:04 ` Brian Gerst
  0 siblings, 1 reply; 30+ messages in thread
From: Petr Vandrovec @ 2002-09-19 17:44 UTC (permalink / raw)
  To: Richard B. Johnson; +Cc: dvorak, linux-kernel

On 19 Sep 02 at 13:22, Richard B. Johnson wrote:

> > >>A short snippet of sys_poll, with irrelavant data removed.
> > >>
> > >>sys_poll(struct pollfd *ufds, .. , ..) {
> > >>    ...
> > >>    ufds++;
> > >>    ...
> 
> Well which one?  Here is an ioctl(). It certainly modifies one
> of its parameter values.

poll(), as was already noted. Program below should
print same value for B= and F=, but it reports f + 8*c instead
(where c = number of filedescriptors passed to poll).

And you must call it from assembly, as your calls to getpid() or
ioctl() (or poll()) are wrapped in libc - and glibc's code begins with
push %ebx because of %ebx is used by -fPIC code.

It is questinable whether we should try to not modify parameters
passed into functions. It is definitely nice behavior, but I think
that we should only guarantee that syscalls do not modify unused
registers.
                                                    Petr Vandrovec
                                                    vandrove@vc.cvut.cz
 
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/poll.h>

struct pollfd f[5];

int main(int argc, char* argv[]) {
    unsigned int i;
    void * reg;

    for (i = 0; i < 5; i++) {
        f[i].fd = 0;
        f[i].events = POLLIN;
    }
    __asm__ __volatile__("int $0x80\n" : "=b"(reg) : "a"(168), "0"(f), "c"(5), "d"(1));
    printf("B=%p F=%p\n", reg, f);
    return 0;
}

^ permalink raw reply	[flat|nested] 30+ messages in thread
* Syscall changes registers beyond %eax, on linux-i386
@ 2002-09-19 14:45 dvorak
  2002-09-19 16:11 ` Richard B. Johnson
  0 siblings, 1 reply; 30+ messages in thread
From: dvorak @ 2002-09-19 14:45 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2095 bytes --]

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

[-- Attachment #2: reg-bug.c --]
[-- Type: text/plain, Size: 1241 bytes --]

/*
 * 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
   ");
}

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2002-09-24 17:59 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-19 17:44 Syscall changes registers beyond %eax, on linux-i386 Petr Vandrovec
2002-09-19 18:04 ` Brian Gerst
2002-09-19 18:30   ` Richard Henderson
2002-09-19 18:51     ` Brian Gerst
2002-09-19 18:57       ` Richard Henderson
2002-09-19 19:40         ` Richard B. Johnson
2002-09-19 19:41           ` Richard Henderson
2002-09-19 19:53             ` Richard B. Johnson
2002-09-19 22:46               ` J.A. Magallon
2002-09-20 12:27                 ` Richard B. Johnson
2002-09-20 17:16                   ` Richard Henderson
2002-09-22  1:33               ` Pavel Machek
2002-09-23 13:11                 ` Richard B. Johnson
2002-09-23 18:31                   ` Pavel Machek
2002-09-19 19:18       ` Richard B. Johnson
2002-09-19 19:24   ` Daniel Jacobowitz
2002-09-19 20:25     ` Mikael Pettersson
2002-09-20  8:32       ` george anzinger
2002-09-21  6:19         ` Richard Henderson
2002-09-21  8:09           ` george anzinger
2002-09-21 15:08             ` Richard Henderson
2002-09-24 18:02             ` CHECKER bate: " george anzinger
  -- strict thread matches above, loose matches on Subject: below --
2002-09-19 14:45 dvorak
2002-09-19 16:11 ` Richard B. Johnson
2002-09-19 17:09   ` Brian Gerst
2002-09-19 17:22     ` Richard B. Johnson
2002-09-19 17:51       ` Brian Gerst
2002-09-19 18:30         ` Richard B. Johnson
2002-09-19 17:59       ` dvorak
2002-09-19 18:32         ` Richard B. Johnson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).