Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 26 Oct 1995 01:06:56 +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:  <199510251506.BAA10257@godzilla.zeta.org.au>

next in thread | raw e-mail | index | archive | help
>> >When a system call is made, arguments are pushed on the user stack
>> >and then the trap vector is called.  There is a necessity to copy
>> ...
>> Only in some ABI's.  This is probably the best way, but it may
>> requires messy conversions in the library to put the args on the
>> stack with consistent padding.

>Pushing on the stack is a messy conversion?  What about dead register

Deciding what to push is messy.  You have to decode the flags that
say where the args are.  This may have to be written in assembler.

>usage from not knowing about the stack?  I think you are going to
>have to burn the cycles on an opaque function call in any case.

I hope that null conversions won't cost anything.  Conversions of
the form `int fd = uap->fd;' (actually machine-generated code to
load fd from an ABI-dependent offset from `void *uap') may even
have a negative cost if they happen to load fd into the right
register at the right time.

>> Since we don't control foreign ABI's we shouldn't assume this.  For
>
>That's fine.  The size of arguments in iBCS2 and BSD is 'int'.  It's
>either 'int' or 'long' or '*'.

Which one?  In NetBSD it's register_t, which may be longer than an
int.  This causes problems.

>So we take a hit when processing these non-standard mechanisms; we do
>so through the system call table for the ABI, so we will be taking
>a function encapsulation hit anyway.

Inlining should remove the hit.  Perhaps given smarter encapsulation
functions, the hit from syscall() could be removed: call the encapsulation
function directly from Xsyscall() and duplicate what syscall() does
(copyin(), etc, iff necessary) in each encapsulation function.

>They are padded to the default bus transfer size for the machine,
>which is supposed to be 'int'.

>I'd argue that 'int' was the wrong size [on the alpha], not that
>there was extraneous
>padding.

This may be true if you control the ABI.

>I'd really dealy love to know how there could be an endianess issue,
>considering system calls are only ever going to run as compiled code
>on one endianess of machine.

To run user code on one machine and syscalls on another.  I wouldn't
want that.

>> >What does it do?  What use is the change?
>> 
>> It avoids scattering unportable casts and ugly macros to perform them
>> throughout the "machine-independent" code.  Now we have only unportable
>> casts.  4.4lite2 has slightly less unportable casts and ugly macros.
>> NetBSD has much less unportable casts and ugly macros.

>The structure casts, I presume?

Yes.

>The answer is to compile with the packing being the default for data
>matchup -- in the alpha case, 64 bits.  For devices that need it, use
>packing #pragma's to tighten them up on a case by case basis, in the
>header file defining the structure.

That won't help much.  The problem is that syscall args don't form
a struct.  Even if they are in memory, the packing may be different.
This can probably be handled by using __attribute__ ((packed)) for
every arg to enforce a particular layout.  But that would only work
with gcc.  I suggest using machine-generated code of the form
`*(type *)(base + OFFSET)' where `type' and OFFSET depend on the arg.

>Aligned element accesses are faster anyway.

OFFSET would usually be a multiple of the alignment so it would be
easy to calculate :-).

>> Earth to Terry :-).  We're talking about inlining syscall handlers, not
>> syscalls.

>Sorry -- you're the one that brought up ABI, which is kernel code, not
>user space code.  The only way you can effect the ABI code is if you
>call the inlined versions and match the user and kernel usage.

The ABI is a convention, and can't be changed.

>> There may be no correct size.  A size of 3 ints wouldn't work for
>> open("foo", 0) if the caller has perversely passed 2 args on the stack
>> at the top of the address space.  Where are the ABI specs that disallow
>> this?

>There are none.  However, you are wrong; it would work, you'd just
>get a garbage value (stack direction grows the right direction for
>the third argument to be optional).  Since in that case the garbage
>value is unreferenced (or the call generated a prototype warning
>...not 8-)), then it will work.

I should get an EFAULT return if the args are at the top of the address
space like I said.

>> >What portability problems do you see in the system call multiplex
>> >interfaces, and under what circumstances can you cause incorrect code
>> >to be generated?
>> 
>> A reasonable parameter passing convention should put the first few
>> args (a fixed number) in registers but stop at the first `...' arg or
>> the one before (so a variable number of args may be in registers.
>> Where are you going to translate this?  Portability problems would
>> result from delaying the translation.  Incorrect code would be generated,
>> as usual, due to bugs.

>I have to point out that it would then be impossible to make system
>calls without prototype references.  If this is a "fix" for the quad
>word passing problem (which is a "non-use of system call prototype"
>problem), then, isn't this just making things worse?

It requires either prototypes or passing parameters of the correct
type just like it always did.  Since there is a lot of broken code
out there, most compilers use inferior parameter passing conventions
to support the broken code.

>Callee pop only works when using the same stack.  When you get to the
>kernel, the kernel thread (or just process) will be using its own stack,
>so that argument won't wash.  My complaint on callee pop as a more
>fruitful pursuit was based on kernel-kernel calls, not user-kernel calls.

Of course you wouldn't want to use it across interfaces, but how do
you stop a C compiler that is optimized for compiling user code from
producing wrong code for interfaces that it doesn't support?  (Writing
masses of interface code in assembler isn't acceptable.)

>Right now the screwable functions are truncate, ftruncate, seek, lseek,
>and mmap -- and mmap() is bogus because of the kernel address space
>restrictions currently on "vmio".  The others are in violation of one
>or more standards because "quad" isn't an allowable type.  Might as
>well violate them further by using inline references to the __syscall(2)
>instead of syscall(2) to get to them so that: (1) they are undefined
>without proper header inclusion, and (2) the padding is guaranteed
>(as the __syscall(2) states in the man page).  That at least would solve
>the screwups without adding to them.

I've thought of changing the compiler to always check format args and
print a diagnostic if there is a mismatch for a quad arg.  Something
similar could be done for the above functions - make them builtins
and complain about type mismatches for them.  For functions it's
easier to silently DTRT (promote the args).

Bruce



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