xref: /llvm-project/libc/src/sys/mman/linux/mmap.cpp (revision a0b65a7bcd6065688189b3d678c42ed6af9603db)
1 //===---------- Linux implementation of the POSIX mmap function -----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/sys/mman/mmap.h"
10 
11 #include "config/linux/syscall.h" // For internal syscall function.
12 #include "include/sys/syscall.h"  // For syscall numbers.
13 #include "src/__support/common.h"
14 #include "src/errno/llvmlibc_errno.h"
15 
16 #include <linux/param.h> // For EXEC_PAGESIZE.
17 
18 namespace __llvm_libc {
19 
20 // This function is currently linux only. It has to be refactored suitably if
21 // mmap is to be supported on non-linux operating systems also.
22 LLVM_LIBC_FUNCTION(void *, mmap,
23                    (void *addr, size_t size, int prot, int flags, int fd,
24                     off_t offset)) {
25   // A lot of POSIX standard prescribed validation of the parameters is not
26   // done in this function as modern linux versions do it in the syscall.
27   // TODO: Perform argument validation not done by the linux syscall.
28 
29   // EXEC_PAGESIZE is used for the page size. While this is OK for x86_64, it
30   // might not be correct in general.
31   // TODO: Use pagesize read from the ELF aux vector instead of EXEC_PAGESIZE.
32 
33 #ifdef SYS_mmap2
34   offset /= EXEC_PAGESIZE;
35   long syscall_number = SYS_mmap2;
36 #elif SYS_mmap
37   long syscall_number = SYS_mmap;
38 #else
39 #error "Target platform does not have SYS_mmap or SYS_mmap2 defined"
40 #endif
41 
42   long ret_val =
43       __llvm_libc::syscall(syscall_number, reinterpret_cast<long>(addr), size,
44                            prot, flags, fd, offset);
45 
46   // The mmap/mmap2 syscalls return negative values on error. These negative
47   // values are actually the negative values of the error codes. So, fix them
48   // up in case an error code is detected.
49   //
50   // A point to keep in mind for the fix up is that a negative return value
51   // from the syscall can also be an error-free value returned by the syscall.
52   // However, since a valid return address cannot be within the last page, a
53   // return value corresponding to a location in the last page is an error
54   // value.
55   if (ret_val < 0 && ret_val > -EXEC_PAGESIZE) {
56     llvmlibc_errno = -ret_val;
57     return MAP_FAILED;
58   }
59 
60   return reinterpret_cast<void *>(ret_val);
61 }
62 
63 } // namespace __llvm_libc
64