Austin Schuh | 36244a1 | 2019-09-21 17:52:38 -0700 | [diff] [blame^] | 1 | // Copyright 2017 The Abseil Authors. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // https://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | // |
| 15 | // Functions for directly invoking mmap() via syscall, avoiding the case where |
| 16 | // mmap() has been locally overridden. |
| 17 | |
| 18 | #ifndef ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ |
| 19 | #define ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ |
| 20 | |
| 21 | #include "absl/base/config.h" |
| 22 | |
| 23 | #if ABSL_HAVE_MMAP |
| 24 | |
| 25 | #include <sys/mman.h> |
| 26 | |
| 27 | #ifdef __linux__ |
| 28 | |
| 29 | #include <sys/types.h> |
| 30 | #ifdef __BIONIC__ |
| 31 | #include <sys/syscall.h> |
| 32 | #else |
| 33 | #include <syscall.h> |
| 34 | #endif |
| 35 | |
| 36 | #include <linux/unistd.h> |
| 37 | #include <unistd.h> |
| 38 | #include <cerrno> |
| 39 | #include <cstdarg> |
| 40 | #include <cstdint> |
| 41 | |
| 42 | #ifdef __mips__ |
| 43 | // Include definitions of the ABI currently in use. |
| 44 | #ifdef __BIONIC__ |
| 45 | // Android doesn't have sgidefs.h, but does have asm/sgidefs.h, which has the |
| 46 | // definitions we need. |
| 47 | #include <asm/sgidefs.h> |
| 48 | #else |
| 49 | #include <sgidefs.h> |
| 50 | #endif // __BIONIC__ |
| 51 | #endif // __mips__ |
| 52 | |
| 53 | // SYS_mmap and SYS_munmap are not defined in Android. |
| 54 | #ifdef __BIONIC__ |
| 55 | extern "C" void* __mmap2(void*, size_t, int, int, int, size_t); |
| 56 | #if defined(__NR_mmap) && !defined(SYS_mmap) |
| 57 | #define SYS_mmap __NR_mmap |
| 58 | #endif |
| 59 | #ifndef SYS_munmap |
| 60 | #define SYS_munmap __NR_munmap |
| 61 | #endif |
| 62 | #endif // __BIONIC__ |
| 63 | |
| 64 | namespace absl { |
| 65 | namespace base_internal { |
| 66 | |
| 67 | // Platform specific logic extracted from |
| 68 | // https://chromium.googlesource.com/linux-syscall-support/+/master/linux_syscall_support.h |
| 69 | inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, |
| 70 | off64_t offset) noexcept { |
| 71 | #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ |
| 72 | (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ |
| 73 | (defined(__PPC__) && !defined(__PPC64__)) || \ |
| 74 | (defined(__s390__) && !defined(__s390x__)) |
| 75 | // On these architectures, implement mmap with mmap2. |
| 76 | static int pagesize = 0; |
| 77 | if (pagesize == 0) { |
| 78 | #if defined(__wasm__) || defined(__asmjs__) |
| 79 | pagesize = getpagesize(); |
| 80 | #else |
| 81 | pagesize = sysconf(_SC_PAGESIZE); |
| 82 | #endif |
| 83 | } |
| 84 | if (offset < 0 || offset % pagesize != 0) { |
| 85 | errno = EINVAL; |
| 86 | return MAP_FAILED; |
| 87 | } |
| 88 | #ifdef __BIONIC__ |
| 89 | // SYS_mmap2 has problems on Android API level <= 16. |
| 90 | // Workaround by invoking __mmap2() instead. |
| 91 | return __mmap2(start, length, prot, flags, fd, offset / pagesize); |
| 92 | #else |
| 93 | return reinterpret_cast<void*>( |
| 94 | syscall(SYS_mmap2, start, length, prot, flags, fd, |
| 95 | static_cast<off_t>(offset / pagesize))); |
| 96 | #endif |
| 97 | #elif defined(__s390x__) |
| 98 | // On s390x, mmap() arguments are passed in memory. |
| 99 | unsigned long buf[6] = {reinterpret_cast<unsigned long>(start), // NOLINT |
| 100 | static_cast<unsigned long>(length), // NOLINT |
| 101 | static_cast<unsigned long>(prot), // NOLINT |
| 102 | static_cast<unsigned long>(flags), // NOLINT |
| 103 | static_cast<unsigned long>(fd), // NOLINT |
| 104 | static_cast<unsigned long>(offset)}; // NOLINT |
| 105 | return reinterpret_cast<void*>(syscall(SYS_mmap, buf)); |
| 106 | #elif defined(__x86_64__) |
| 107 | // The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. |
| 108 | // We need to explicitly cast to an unsigned 64 bit type to avoid implicit |
| 109 | // sign extension. We can't cast pointers directly because those are |
| 110 | // 32 bits, and gcc will dump ugly warnings about casting from a pointer |
| 111 | // to an integer of a different size. We also need to make sure __off64_t |
| 112 | // isn't truncated to 32-bits under x32. |
| 113 | #define MMAP_SYSCALL_ARG(x) ((uint64_t)(uintptr_t)(x)) |
| 114 | return reinterpret_cast<void*>( |
| 115 | syscall(SYS_mmap, MMAP_SYSCALL_ARG(start), MMAP_SYSCALL_ARG(length), |
| 116 | MMAP_SYSCALL_ARG(prot), MMAP_SYSCALL_ARG(flags), |
| 117 | MMAP_SYSCALL_ARG(fd), static_cast<uint64_t>(offset))); |
| 118 | #undef MMAP_SYSCALL_ARG |
| 119 | #else // Remaining 64-bit aritectures. |
| 120 | static_assert(sizeof(unsigned long) == 8, "Platform is not 64-bit"); |
| 121 | return reinterpret_cast<void*>( |
| 122 | syscall(SYS_mmap, start, length, prot, flags, fd, offset)); |
| 123 | #endif |
| 124 | } |
| 125 | |
| 126 | inline int DirectMunmap(void* start, size_t length) { |
| 127 | return static_cast<int>(syscall(SYS_munmap, start, length)); |
| 128 | } |
| 129 | |
| 130 | } // namespace base_internal |
| 131 | } // namespace absl |
| 132 | |
| 133 | #else // !__linux__ |
| 134 | |
| 135 | // For non-linux platforms where we have mmap, just dispatch directly to the |
| 136 | // actual mmap()/munmap() methods. |
| 137 | |
| 138 | namespace absl { |
| 139 | namespace base_internal { |
| 140 | |
| 141 | inline void* DirectMmap(void* start, size_t length, int prot, int flags, int fd, |
| 142 | off_t offset) { |
| 143 | return mmap(start, length, prot, flags, fd, offset); |
| 144 | } |
| 145 | |
| 146 | inline int DirectMunmap(void* start, size_t length) { |
| 147 | return munmap(start, length); |
| 148 | } |
| 149 | |
| 150 | } // namespace base_internal |
| 151 | } // namespace absl |
| 152 | |
| 153 | #endif // __linux__ |
| 154 | |
| 155 | #endif // ABSL_HAVE_MMAP |
| 156 | |
| 157 | #endif // ABSL_BASE_INTERNAL_DIRECT_MMAP_H_ |