This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
AW: AW: Renesas __trap34() system calls broken - possibly on other platforms, too
- From: "Jonas Mark (ST-FIR/ENG1)" <Mark dot Jonas at de dot bosch dot com>
- To: "Dave Korn" <dave dot korn at artimi dot com>, <newlib at sourceware dot org>
- Cc: "Andrew STUBBS" <andrew dot stubbs at st dot com>
- Date: Thu, 11 Jan 2007 09:30:11 +0100
- Subject: AW: AW: Renesas __trap34() system calls broken - possibly on other platforms, too
Hello Dave,
>> No, it is not about hand-coded assembler code. The __trap34()
>> implementation in trap.S is overwritten during link time by my code.
>> syscalls.c is C language and my code is as well (see my first post).
>> My code implements the variadic function __trap34(). Because it only
>> has an implicit function prototype in syscalls.c the compiler cannot
>> know it is variadic and therefore rightly does not produce matching
>> code.
>
> It's undefined behaviour to call an unprototyped variadic function.
> Fix that and your problem should be solved.
>
>>>> I do not think gcc is broken. How should the compiler know when to
>>>> put all parameters on the stack because it is a variable argument
>>>> list function?
>
> The prototype tells the compiler where to put the args. That's why
> it's undefined if you attempt to call it in the absence of a
> prototype.
Well, that's what I have been saying from the beginning: __trap34()
lacks a prototype.
What I did wrong from the beginning was to look at the places where
__trap34() is called and deduced from that what the prototype for
__trap34() is. I saw, that there is not one but there are 15 prototypes,
which not only differ in the count of arguments, but also in the type of
the arguments, except for the first:
SYS_fork, SYS_wait: int __trap34(int)
SYS_argc: int __trap34(int)
SYS_argnlen: int __trap34(int, int)
SYS_pipe: int __trap34(int, int*)
SYS_argn: int __trap34(int, int, char*)
SYS_chmod: int __trap34(int, const char*, short)
SYS_utime: int __trap34(int, const char*, char*)
SYS_execv: int __trap34(int, const char*, char *const[])
SYS_read, SYS_write: int __trap34(int, int, char*, int)
SYS_lseek, SYS_close: int __trap34(int, int, int, int)
SYS_ftruncate: int __trap34(int, int, off_t, int)
SYS_open, SYS_create: int __trap34(int, const char*, int, int)
SYS_chown: int __trap34(int, const char*, short, short)
SYS_truncate: int __trap34(int, const char*, off_t, int)
SYS_stat: int __trap34(int, const char*, struct stat*, int)
And that was the point where I came to the conclusion that __trap34()
must be variadic.
What I learned is, that the code makes use of the fact that not
specifying a prototype can be used to declare a pseudo-variadic
function. With the knowledge that both the GCC and the Renesas SH7720
ABI always put the first four parameters in four separate registers,
this allows a hand-coded assembler routine to easily pick up the
parameters from registers instead of retrieving them from the stack.
IMHO this is a hack, but I admit it works and allows a very compact
assembler implementation.
So my solution will be to declare my C implementation as __trap34(int,
int, int, int) and will later cast the last three ints to whatever the
system call really meant to pass. This, of course, is prone to break
when ported to a different ABI, but the hand-coded assembler will break
in that case as well.
Thank you for the discussion.
Regards,
Mark Jonas