home bbs files messages ]

Forums before death by AOL, social media and spammers... "We can't have nice things"

   comp.arch      Apparently more than just beeps & boops      131,241 messages   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]

   Message 129,389 of 131,241   
   Dan Cross to Anton Ertl   
   Re: System calls (was: VAX)   
   13 Aug 25 19:25:31   
   
   From: cross@spitfire.i.gajendra.net   
      
   In article <2025Aug13.181010@mips.complang.tuwien.ac.at>,   
   Anton Ertl  wrote:   
   >scott@slp53.sl.home (Scott Lurndal) writes:   
   >>anton@mips.complang.tuwien.ac.at (Anton Ertl) writes:   
   >>>scott@slp53.sl.home (Scott Lurndal) writes:   
   >>>>That said, Unix generally defined -1 as the return value for all   
   >>>>other system calls, and code that checked for "< 0" instead of   
   >>>>-1 when calling a standard library function or system call was   
   fundamentally   
   >>>>broken.   
   >>>   
   >>>That may be the interface of the C system call wrapper,   
   >>   
   >>It _is_ the interface that the programmers need to be   
   >>concerted with when using POSIX C language bindings.   
   >   
   >True, but not relevant for the question at hand.   
   >   
   >>>at the actual system call level, the error is indicated in   
   >>>an architecture-specific way, and the ones I have looked at before   
   >>>today use the sign of the result register or the carry flag.  On those   
   >>>architectures, where the sign is used, mmap(2) cannot return negative   
   >>>addresses, or must have a special wrapper.   
   >>   
   >>Why would the wrapper care if the system call failed?   
   >   
   >The actual system call returns an error flag and a register.  On some   
   >architectures, they support just a register.  If there is no error,   
   >the wrapper returns the content of the register.  If the system call   
   >indicates an error, you see from the value of the register which error   
   >it is; the wrapper then typically transforms the register in some way   
   >(e.g., by negating it) and stores the result in errno, and returns -1.   
   >   
   >>lseek(2) and mmap(2) both require the return of arbitrary 32-bit   
   >>or 64-bit values, including those which when interpreted as signed   
   >>values are negative.   
   >   
   >For lseek(2):   
   >   
   >| Upon successful completion, lseek() returns the resulting offset   
   >| location as measured in bytes from the beginning of the file.   
   >   
   >Given that off_t is signed, lseek(2) can only return positive values.   
      
   This is incorrect; or rather, it's accidentally correct now, but   
   was not previously.  The 1990 POSIX standard did not explicitly   
   forbid a file that was so large that the offset couldn't   
   overflow, hence why in 1990 POSIX you have to be careful about   
   error handling when using `lseek`.   
      
   It is true that POSIX 2024 _does_ prohibit seeking so far that   
   the offset would become negative, however.  But, POSIX 2024   
   (still!!) supports multiple definitions of `off_t` for multiple   
   environments, in which overflow is potentially unavoidable.   
   This leads to considerable complexity in implementations that   
   try to support such multiple environments in their ABI (for   
   instance, for backwards compatability with old programs).   
      
   >For mmap(2):   
   >   
   >| On success, mmap() returns a pointer to the mapped area.   
   >   
   >So it's up to the kernel which user-level addresses it returns.  E.g.,   
   >32-bit Linux originally only produced user-level addresses below 2GB.   
   >When memories grew larger, on some architectures (e.g., i386) Linux   
   >increased that to 3GB.   
      
   The point is that the programmer shouldn't have to care.  The   
   programmer should check the return value against MAP_FAILED, and   
   if it is NOT that value, then the returned address may be   
   assumed valid.  If such an address is not actually valid, that   
   indicates a bug in the implementation of `mmap`.   
      
   >>Clearly POSIX defines the interfaces and the underlying OS and/or   
   >>library functions implement the interfaces.   The kernel interface   
   >>to the language library (e.g. libc) is irrelevent to typical programmers   
   >   
   >Sure, but system calls are first introduced in real kernels using the   
   >actual system call interface, and are limited by that interface.  And   
   >that interface is remarkably similar between the early days of Unix   
   >and recent Linux kernels for various architectures.   
      
   Not precisely.  On x86_64, for example, some Unixes use a flag   
   bit to determine whether the system call failed, and return   
   (positive) errno values; Linux returns negative numbers to   
   indicate errors, and constrains those to values between -4095   
   and -1.   
      
   Presumably that specific set of values is constrained by `mmap`:   
   assuming a minimum 4KiB page size, the last architecturally   
   valid address where a page _could_ be mapped is equivalent to   
   -4096 and the first is 0.  If they did not have that constraint,   
   they'd have to treat `mmap` specially in the system call path.   
      
   Linux _could_ decide to define `MAP_FAILED` as   
   0x0fff_ffff_0000_0000, which is non-canonical on all extant   
   versions of x86-64, even with 5-level paging, but maybe they do   
   not because they're anticipating 6-level paging showing up at   
   some point.   
      
   >And when you look   
   >closely, you find how the system calls are design to support returning   
   >the error indication, success value, and errno in one register.   
   >   
   >lseek64 on 32-bit platforms is an exception (the success value does   
   >not fit in one register), and looking at the machine code of the   
   >wrapper and comparing it with the machine code for the lseek wrapper,   
   >some funny things are going on, but I would have to look at the source   
   >code to understand what is going on.  One other interesting thing I   
   >noticed is that the system call wrappers from libc-2.36 on i386 now   
   >draws the boundary between success returns and error returns at   
   >0xfffff000:   
   >   
   >   0xf7d853c4 :       call   *%gs:0x10   
   >   0xf7d853cb :       cmp    $0xfffff000,%eax   
   >   0xf7d853d0 :       ja     0xf7d85410    
   >   
   >So now the kernel can produce 4095 error values, and the rest can be   
   >success values.  In particular, mmap() can return all possible page   
   >addresses as success values with these wrappers.  When I last looked   
   >at how system calls are done, I found just a check of the N or the C   
   >flag.   
      
   Yes; see above.   
      
   >I wonder how the kernel is informed that it can now return more   
   >addresses from mmap().   
      
   Assuming you mean the Linux kernel, when it loads an ELF   
   executable, the binary image itself is "branded" with an ABI   
   type that it can use to make that determination.   
      
   	- Dan C.   
      
   --- SoupGate-Win32 v1.05   
    * Origin: you cannot sedate... all the things you hate (1:229/2)   

[   << oldest   |   < older   |   list   |   newer >   |   newest >>   ]


(c) 1994,  bbs@darkrealms.ca