On Wed, Dec 12, 2018 at 8:52 AM Rich Felker <dalias@xxxxxxxx> wrote: > > On Wed, Dec 12, 2018 at 08:39:53AM -0800, Andy Lutomirski wrote: > > > On Dec 11, 2018, at 6:33 PM, Thorsten Glaser <tg@xxxxxxxxx> wrote: > > > > > > Andy Lutomirski dixit: > > > > > > > > > > >> IMO the real right solution would be to push the whole problem to > > >> userspace: get an ILP32 system working with almost or entirely LP64 > > > > > > Is this a reflex of Linux kernel developers? ;-) > > > > > > I doubt that userspace is the right place for this, remember > > > the recent glibc vs. syscalls debate. It would also need to > > > multiply across various libcs. > > > > > >> How hard would it be to have __attribute__((ilp64)), with an optional > > >> warning if any embedded structs are not ilp64? This plus a wrapper to > > > > > > You mean LP64. Impossible, because LP64 vs. ILP32 is not the only > > > difference between amd64 and x32. > > > > I mean LP64. And I'm not suggesting that ILP32 is the only difference > > between x32 and x86_64, nor am I suggesting that a technique like this > > would implement x32 -- I'm suggesting it would implement something > > better than x32. > > > > The kernel, as a practical matter, supports two ABIs on 64-bit builds: > > LP64 and ILP32. ILP32 is what the kernel calls "compat". ("compat" > > comes with other baggage -- it generally has a 32-bit signal frame, > > syscall arguments are mostly limited to 32 bits, etc.) Allowing a > > user program that runs in 64-bit mode to issue compat syscalls is not > > really a big deal. x86_64 has allowed this forever using int $0x80 -- > > it's just slow. Adding a faster mechanism would be straightforward. > > As I understand it, the arm64 ilp32 proposal involves using a genuine > > ILP32 model for user code, so the syscalls will all (except for signal > > handling) go through the compat path. > > > > x32 is not this at all. The kernel ABI part of x32 isn't ILP32. It's > > IP32, 32-bit size_t, and *64-bit* long. The core kernel doesn't > > really support this. The only good things I can think of about it are > > that (a) it proves that somewhat odd ABIs are possible, at least in > > principle, and (b) three users have come out of the woodwork to say > > that they use it. > > > > I'm proposing another alternative. Given that x32 already proves that > > the user bitness model doesn't have to match the kernel model (in x32, > > user "long" is 32-bit but the kernel ABI "long" is 64-bit), I'm > > proposing extending this to just make the kernel ABI be LP64. So > > __kernel_size_t would be 64-bit and pointers in kernel data structures > > would be 64-bit. In other words, most or all of the kernel ABI would > > just match x86_64. > > > > As far as I can tell, the only thing that really needs unusual > > toolchain features here is that C doesn't have an extra-wide pointer > > type. The kernel headers would need a way to say "this pointer is > > still logically a pointer, and user code may assume that it's 32 bits, > > but it has 8-byte alignment." > > None of this works on the userspace/C side, nor should any attempt be > made to make it work. Types fundamentally cannot have alignments > larger than their size. If you want to make the alignment of some > pointers 8, you have to make their size 8, and then you just have LP64 > again if you did it for all pointers. > > If on the other hand you tried to make just some pointers "wide > pointers", you'd also be completely breaking the specified API > contracts of standard interfaces. For example in struct iovec's > iov_base, &foo->iov_base is no longer a valid pointer to an object of > type void* that you can pass to interfaces expecting void**. Sloppy > misunderstandings like what you're making now are exactly why x32 is > already broken and buggy (&foo->tv_nsec already has wrong type for > struct timespec foo). I don't think it's quite that broken. For the struct iovec example, we currently have: struct iovec { void *iov_base; /* Starting address */ size_t iov_len; /* Number of bytes to transfer */ }; we could have, instead: (pardon any whitespace damage) struct iovec { void *iov_base; /* Starting address */ uint32_t __pad0; size_t iov_len; /* Number of bytes to transfer */ uint32_t __pad1; } __attribute__((aligned(8)); or the same thing but where iov_len is uint64_t. A pointer to iov_base still works exactly as expected. Something would need to be done to ensure that the padding is all zeroed, which might be a real problem. No one wants to actually type all the macro gunk into the headers to make this work, but this type of transformation is what I have in mind when the compiler is asked to handle the headers. Or there could potentially be a tool that automatically consumes the uapi headers and spits out modified headers like this. Realistically, I think a much better model would be to use true ILP32 code, where all the memory layouts in the uapi match i386. > Unless it's a thin, "pure" library that doesn't need anything from > libc, or needs sufficiently little that it could be satisfied by some > shims, this would necessarily require having two libcs in the same > process, which is not going to work. > > That's a good point.