xref: /llvm-project/libc/src/sys/mman/linux/mmap.cpp (revision 5ff3ff33ff930e4ec49da7910612d8a41eb068cb)
1ec62bf2fSSiva Chandra Reddy //===---------- Linux implementation of the POSIX mmap function -----------===//
2ec62bf2fSSiva Chandra Reddy //
3ec62bf2fSSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ec62bf2fSSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5ec62bf2fSSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ec62bf2fSSiva Chandra Reddy //
7ec62bf2fSSiva Chandra Reddy //===----------------------------------------------------------------------===//
8ec62bf2fSSiva Chandra Reddy 
9ec62bf2fSSiva Chandra Reddy #include "src/sys/mman/mmap.h"
10ec62bf2fSSiva Chandra Reddy 
113cc2161cSSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
12ec62bf2fSSiva Chandra Reddy #include "src/__support/common.h"
13ec62bf2fSSiva Chandra Reddy 
14*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
15204587a3SSiva Chandra Reddy #include "src/errno/libc_errno.h"
16ec62bf2fSSiva Chandra Reddy #include <linux/param.h> // For EXEC_PAGESIZE.
17134e9d19SSiva Chandra Reddy #include <sys/syscall.h> // For syscall numbers.
18ec62bf2fSSiva Chandra Reddy 
19*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
20ec62bf2fSSiva Chandra Reddy 
21ec62bf2fSSiva Chandra Reddy // This function is currently linux only. It has to be refactored suitably if
22ec62bf2fSSiva Chandra Reddy // mmap is to be supported on non-linux operating systems also.
23a0b65a7bSMichael Jones LLVM_LIBC_FUNCTION(void *, mmap,
24a0b65a7bSMichael Jones                    (void *addr, size_t size, int prot, int flags, int fd,
25a0b65a7bSMichael Jones                     off_t offset)) {
26ec62bf2fSSiva Chandra Reddy   // A lot of POSIX standard prescribed validation of the parameters is not
27ec62bf2fSSiva Chandra Reddy   // done in this function as modern linux versions do it in the syscall.
28ec62bf2fSSiva Chandra Reddy   // TODO: Perform argument validation not done by the linux syscall.
29ec62bf2fSSiva Chandra Reddy 
30ec62bf2fSSiva Chandra Reddy   // EXEC_PAGESIZE is used for the page size. While this is OK for x86_64, it
31ec62bf2fSSiva Chandra Reddy   // might not be correct in general.
32ec62bf2fSSiva Chandra Reddy   // TODO: Use pagesize read from the ELF aux vector instead of EXEC_PAGESIZE.
33ec62bf2fSSiva Chandra Reddy 
34ec62bf2fSSiva Chandra Reddy #ifdef SYS_mmap2
35ec62bf2fSSiva Chandra Reddy   offset /= EXEC_PAGESIZE;
36ec62bf2fSSiva Chandra Reddy   long syscall_number = SYS_mmap2;
375b22df99SMikhail R. Gadelha #elif defined(SYS_mmap)
38ec62bf2fSSiva Chandra Reddy   long syscall_number = SYS_mmap;
39ec62bf2fSSiva Chandra Reddy #else
405b22df99SMikhail R. Gadelha #error "mmap or mmap2 syscalls not available."
41ec62bf2fSSiva Chandra Reddy #endif
42ec62bf2fSSiva Chandra Reddy 
437776fba4SMikhail R. Gadelha   // We add an explicit cast to silence a "implicit conversion loses integer
447776fba4SMikhail R. Gadelha   // precision" warning when compiling for 32-bit systems.
457776fba4SMikhail R. Gadelha   long mmap_offset = static_cast<long>(offset);
46f0a3954eSMichael Jones   long ret =
47b6bc9d72SGuillaume Chatelet       LIBC_NAMESPACE::syscall_impl(syscall_number, reinterpret_cast<long>(addr),
487776fba4SMikhail R. Gadelha                                    size, prot, flags, fd, mmap_offset);
49ec62bf2fSSiva Chandra Reddy 
50ec62bf2fSSiva Chandra Reddy   // The mmap/mmap2 syscalls return negative values on error. These negative
51ec62bf2fSSiva Chandra Reddy   // values are actually the negative values of the error codes. So, fix them
52ec62bf2fSSiva Chandra Reddy   // up in case an error code is detected.
53ec62bf2fSSiva Chandra Reddy   //
54ec62bf2fSSiva Chandra Reddy   // A point to keep in mind for the fix up is that a negative return value
55ec62bf2fSSiva Chandra Reddy   // from the syscall can also be an error-free value returned by the syscall.
56ec62bf2fSSiva Chandra Reddy   // However, since a valid return address cannot be within the last page, a
57ec62bf2fSSiva Chandra Reddy   // return value corresponding to a location in the last page is an error
58ec62bf2fSSiva Chandra Reddy   // value.
59f0a3954eSMichael Jones   if (ret < 0 && ret > -EXEC_PAGESIZE) {
60f0a3954eSMichael Jones     libc_errno = static_cast<int>(-ret);
61ec62bf2fSSiva Chandra Reddy     return MAP_FAILED;
62ec62bf2fSSiva Chandra Reddy   }
63ec62bf2fSSiva Chandra Reddy 
64f0a3954eSMichael Jones   return reinterpret_cast<void *>(ret);
65ec62bf2fSSiva Chandra Reddy }
66ec62bf2fSSiva Chandra Reddy 
67*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
68