On Thu, Sep 19, 2002 at 01:22:35PM -0400, Richard B. Johnson wrote: > On Thu, 19 Sep 2002, Brian Gerst wrote: > > > Richard B. Johnson wrote: > > > On Thu, 19 Sep 2002, dvorak wrote: > > > > > > > > >>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' > > >> > > >>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. > > >> > > > > > > > > > The 'C' compiler must make room on the stack for any local > > > variables except register types. If it was doing as you state, you > > > couldn't even execute a "hello world" program. Further, the local > > > variables are after the return address. It would screw up the return > > > address and you'd go off into hyper-space upon return. The problem is it uses one of the _arguments_ passed to the function, that argument gets modified, normally this happens on a copy, but there is no 'garantue' that is doesn't modify the original argument as putted on the stack by the calling function. > > > No. Various 'C' implementers have standardized calling methods even > > > though it's not part of the 'C' standard. gcc and others assume that > > > a called procedure is not going to change any segments or index registers. > > > There are various optimization things, like "-fcaller-saves" where the > > > called procedure can destroy anything. You may be using something that > > > was wrongly compiled using that switch. This is not what happens here, what happens is that one of the _arguments_ placed on the stack is being modified, normally a calling function discards these values after use (addl $0x10, %esp or similar) but in this case they are reused. (in the RESTORE_ALL call) > > > > The bug is only with _some_ syscalls, and getpid() is not one of them, > > so your example is flawed. It happens when a syscall modifies one of > > it's parameter values. The solution is to assign the parameter to a > > local variable before modifying it. > > and only with _some_ compiler + kernel combinations. > int main() > { > struct termios t; > > __asm__ __volatile__("movl $0xdeadface, %ebx\n"); > (void)ioctl(0, TCGETS, &t); > (void)getpid(); > __asm__ __volatile__("cmpl $0xdeadface, %ebx\n" > "jnz barf\n"); > > return 0; > } > Until you can show the syscall that doesn't follow the correct > rules, then my example is not flawed. In fact a modified example can > be used to find any broken calls. I putted in some assembler code in my original post that uses the sys_poll syscall of which i _know_ it modifies one of it's arguments, to be more specific, it's first argument, which is %ebx on passing in: asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, long timeout) .... for(i=0; i < (int)nfds; i++, ufds++, fds1++) { .... and in fact we saw that the change in %ebx is proportional to the nfds as passed to sys_poll. now however for sys_ioctl: it's first argument, fd (%ebx on passing) is never modifed in the code nowhere is there an fd++ or similar, so again this 'example' of yours is flawed. gtx. dvorak P.S. i think my original was quite clear and INCLUDED example code that can easily be checked by someone who reads asm, i attach an extra copy which explains all the asm in there for easier reference.