Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Mon, 20 Jan 2014 18:57:00 -0500
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: Re: Discussion of partly-invasive changes needed for x32 port

On Mon, Jan 20, 2014 at 11:55:39AM +0100, Jens Gustedt wrote:
> Am Montag, den 20.01.2014, 11:12 +0100 schrieb John Spencer:
> > what rich had in mind was usage of _Generic in the x32 __scc 
> > (syscall-cast) macro:
> > 
> > instead of
> > 
> > #define __scc(X) sizeof(1?(X):0ULL) < 8 ? (unsigned long) (X) : (long 
> > long) (X)
> > 
> > something along the lines of
> > _Generic((X), struct timespec*: &(struct timespec){.sec = (X).sec, .nsec 
> > = (X).nsec}, default: sizeof(1?(X):0ULL) < 8 ? (unsigned long) (X) : 
> > (long long) (X))
> 
> ah, I see how _Generic could pop in an make some wrappers for
> architecture specific code nicer
> 
> In the concrete case I don't understand too well. The return type of
> that generic expression would be of a fundamentally different type,
> once a pointer to struct, otherwise an integer. Also the two struct
> types should be different types, no? One the userland type and the
> other the kernel type?

Both the pointer to struct and the integer case would be converted to
integers as in the the above "current" version of the __scc macro.

> But then something like
> 
> &(struct kernel_timespec){.sec = (X)->sec, .nsec = (X)->nsec}
> 
> should suffice to capture the transition well.
> 
> This would certainly benefit of a wrapper function
> kernel_timespec_copy, because it evaluates X twice :
> 
> 
> kernel_timespec_copy(&(struct kernel_timespec){0}, (X))

Evaluating X twice is not really a big deal, because it's never going
to be an expression that would have side effects. But I agree having
the (inline) wrapper function there is a nicer approach, and the
compiler should generate equally efficient code.

> If you want that for optimization reasons you could try to capture if
> the two types agree and avoid the extra copy. Something along the
> line of
> 
> _Generic((X),
>         struct kernel_timespec*: (X),
>          default: kernel_timespec_copy(&(struct kernel_timespec*){0}, (X))
>         )
> 
> But I am not convinced that this can't be just achieved by doing some
> #ifdef programming

Where? In every file that passes timespecs to syscalls? The whole
point is to follow my basic principle that workarounds for buggy
platforms (which the kernel's x32 support is) belong in places where
nobody has to see them unless they're working with the buggy platform
in question. This is a principle I first proposed and promoted while
working on MPlayer, and later applied as a critique of frameworks like
NSPR, APR, etc. The classic example of this principle goes like this:
For a cross-platform application or library, instead of having #ifdef
WIN32 all over the place and windows-specific code interleaved all
over the general, non-platform-specific code, one should provide
replacement headers or library code that fix the behavior of the
windows headers or runtime to conform to the standards they're
ignoring, and then write the code shared between platforms to portable
C/POSIX. BTW in some ways gnulib also follows this principle, except
that it assumes by default the target system is broken and needs fixes
which are inherently non-portabke. If you instead assume by default
that the target is non-broken, and only apply fixes to a known finite
set of broken platforms, you have much less chance of breaking things
and also keep the ugly hacks out of the way of developers not
specifically dealing with porting to the broken system(s).

That's the motivation here.

> > however the only available compiler implementing _Generic is Clang.
> > not even GCC 4.8.2 supports it. however i've seen some pseudo _Generic 
> > implementation on your blog [1], imo we could use the bits described 
> > there, namely
> > "
> >      __typeof__(EXP) gives the type of the expression EXP
> >      __builtin_types_compatible_p(T1, T2) is true if the two types are 
> > compatible
> >      __builtin_choose_expr(CNTRL, EXP1, EXP2) choose between the two 
> > expressions at compile time.
> > "
> > 
> > to implement the above macro, as x32 requires a very recent GCC (>= 4.7) 
> > anyway, i see no big problem in using those gcc helpers in lieu of _Generic.
> 
> These features are supported since long in gcc and clang, I think, so
> yes from that side there certainly would be not much of an obstacle.
> 
> But I wouldn't think that using such a feature just in such an
> isolated spot (very restricted part of code and very specific
> architecture) would be worth it.

Yes, I think this is reasonable.

> Some cooked down version of _Generic could perhaps be beneficial for
> the whole of musl, there are some places that implement type
> genericity in some handcrafted way. But these things need macro magic
> and should not be re-implemented at each point where they are
> needed. So probably much too intrusive at this point in time.

Right now the only magic type-generic macros in musl are in tgmath.h
and internal/syscall.h. So I think we're okay without any more general
_Generic framework for now.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.