Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 Oct 1995 07:57:34 +1000
From:      Bruce Evans <bde@zeta.org.au>
To:        bde@zeta.org.au, terry@lambert.org
Cc:        CVS-commiters@freefall.freebsd.org, bde@freefall.freebsd.org, cvs-sys@freefall.freebsd.org, hackers@freebsd.org, swallace@ece.uci.edu
Subject:   Re: SYSCALL IDEAS [Was: cvs commit: src/sys/kern sysv_msg.c sysv_sem.c sysv_shm.c]
Message-ID:  <199510272157.HAA29637@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>> All #pragmas are unportable.

>All packing assumptions are unportable.  I argue that a #pragma beats
>the __attrib crap because a compiler may ignore it.

A compiler may exec /usr/games/hack to handle every pragma.  gcc used
to do this.

>>     path = *(char const *)((char *)argp + PATH_OFFSET);
>>     flags = *(int *)((char *)argp + FLAGS_OFFSET);
>> 	mode = *(promoted_mode_t *)((char *)argp + MODE_OFFSET);

>Forgive me... but this is butt-ugly.  I mean really, *really* butt-ugly.

>I find this horribly obfucated.  This is exactly what I feared when I
>objected.  8-(.

It's machine generated.  It looks better than va_arg().  Don't look at it.

>BTW: the 'path' line is broken... "*(const char **)", maybe?

Oops.

>Since the stack variable assigns are based on an entry argument, then
>the assignments can be done at declaration time.  Therefore something
>like:

>#define	ARG(argtype,arg)						\
>	argtype arg = *(__CONCAT(argtype,*))((char *)argp +		\
>		      __CONCAT(arg,_OFFSET));

Assignment at declaration time is consider bad style by the 4.4lite2
style guide and by me.

The offsets would actually be literal numbers.  They are too hard to
create using macros.

>I don't understand why passing a bogus mode to open when O_CREAT wasn't
>present would be a problem???

>That is, why not:

>> int syscall_entry_open(struct proc *p, void *argp, int *retval)
>> {
>>     ARG( char const *,	PATH);
>>     ARG( int,			FLAGS);
>>     ARG( promoted_mode_t,	MODE);
>>
>>     return open(p, retval, PATH, FLAGS, MODE);
>> }

The last ARG() might cause a fatal trap if the arg doesn't exist.  It
might be worth guaranteeing that argp points to a safe place to ARG()
can't trap here.  But then the caller might have to do more work to
provide a safe place or recover from the trap.  This is currently
handled very efficiently by copyin() recovering from traps if the user
doesn't supply enough args.

>Hell:

>#define	SYSCALL_ENTRY(function)						\
>	int __CONCAT(syscall_entry_,function)				\
>			(struct proc *p, void *argp, int *retval)

>> SYSCALL_ENTRY(open)
>> {
>>     ARG( char const *,	PATH);
>>     ARG( int,			FLAGS);
>>     ARG( promoted_mode_t,	MODE);
>>
>>     return open(p, retval, PATH, FLAGS, MODE);
>> }

This would require large table of #defines of OFFSETs.  I prefer to use
literal offsets.

>I know the XDR aspects re structure packing are an issue, though since
>you seem to be assuming the same compiler source everywhere (GCC),

No, the OFFSETs depend on the compiler.  I assumed the same endianness
in my example, but endianness changes can be handled by more complicated
ARG() code.  Pointer alignment for *(foo_t *) is unlikely to be a problem
because the args are usually laid out so that they can be accessed.

>I don't see where a packing paragma would be more of an issue than
>any other approach requiring compiler modifications.

It would take about the same work to machine-generate all the pragmas
and padding as to machine-generate all the offsets, e.g.,

#pragma pack(0) /* or whatever stops all packing */
struct read_args {
	char const *path;
	int flags;
	char pad1[4];		/* little endian, 4 byte ints, 8 byte regs */
	mode_t mode;
	char pad2[6];
};

vs.

#define read_path_OFFSET	0
#define read_path_type		char const *
#define read_flags_OFFSET	8
#define read_flags_type		int
#define read_mode_OFFSET	16
#define read_mode_type		mode_t

>> The register passing mechanism for syscalls is a side issue.  I only
>> mentioned it as an example of an ABI that we have to emulate (for Linux)
>> and which is better so we should use it.  There would be no new
>> complications (except for improvements) because we already support the
>> Linux ABI.

>I'm glad to see this.  I think, though, the rationale for the changes
>still hasn't been clarified.

`lcall' allow users to trace into syscalls.  This can be recovered from
but is ugly.  Trap gates don't have this problem.  NetBSD and Linux
already use trap gates for their native system calls and we don't want
to be uglier or slower than NetBSD or Linux :-).  We need to support
trap gates for emulation anyway.  If we change to trap gates then we
should consider changing other parts of the syscall interface.  We don't
need to copy NetBSD's or Linux's interface except for emulation.

>This was my point on the quad crap and reverting the default interfaces
>to POSIX compliance (and double doesn't count unless you can use it
>without a prototype in scope).

	if (lseek(fd, (off_t)foo, SEEK_SET) == (off_t)-1)
		perror("lseek");

works without a prototype in scope even if off_t is quad or double.

>> syscall() is written in C, so the compiler can pass args to it anywhere it
>> wants.  syscall() then has the task of putting the args where the kernel
>> expects them.  In general, it would have to know about all syscalls and
>> do the inverse of the conversions that I'm talking about doing in the
>> kernel.

>Bletch.  How does Linux deal with it (my linux box is running Win95
>right now)?

i386's are enough like vaxes and gcc uses stupid enough function call
conventions for there to be no problems.  Just put the first arg in
the first register, etc.

>> Consider a 68K compiler that passes the first 2 pointer args (if any)
>> in a0-a1 and the first 2 integer args (if any) in d0-d1 and the other
>> args on the stack.  How are you going to push the args in syscall()?
>> Hint: you'll need to know the arg types of all syscalls.

>That's an evil way to pass arguments, then.  8-(.

But not stupid :-).

>> It's worse than that.  Linux doesn't have quads.  Applications have to use
>> pairs of longs and do their own (equivalent to quad) arithmetic on them.
>> So ifdefs like the above all through the code might be necessary.

>Linux has GCC.  Linux has quads.

I thought it doesn't use them for llseek.  I guess it doesn't matter.
Two longs together look like a quad.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199510272157.HAA29637>