]>
Commit | Line | Data |
---|---|---|
ed23bd30 | 1 | /* Darwin host-specific hook definitions. |
aeee4812 | 2 | Copyright (C) 2003-2023 Free Software Foundation, Inc. |
ed23bd30 GK |
3 | |
4 | This file is part of GCC. | |
5 | ||
6 | GCC is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published | |
2f83c7d6 | 8 | by the Free Software Foundation; either version 3, or (at your |
ed23bd30 GK |
9 | option) any later version. |
10 | ||
11 | GCC is distributed in the hope that it will be useful, but WITHOUT | |
12 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
14 | License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
2f83c7d6 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
ed23bd30 GK |
19 | |
20 | #include "config.h" | |
21 | #include "system.h" | |
22 | #include "coretypes.h" | |
22a98240 | 23 | #include "options.h" |
718f9c0f | 24 | #include "diagnostic-core.h" |
ed23bd30 | 25 | #include "config/host-darwin.h" |
22a98240 IS |
26 | #include <errno.h> |
27 | ||
28 | /* For Darwin (macOS only) platforms, without ASLR (PIE) enabled on the | |
29 | binaries, the following VM addresses are expected to be available. | |
30 | NOTE, that for aarch64, ASLR is always enabled - but the VM address | |
31 | mentioned below is available (at least on Darwin20). | |
32 | ||
33 | The spaces should all have 512Mb available c.f. PCH files for large | |
34 | C++ or Objective-C in the range of 150Mb for 64b hosts. | |
35 | ||
0d5db1dd IS |
36 | We also try to steer clear of places already used for sanitizers. |
37 | ||
38 | If the allocation fails at the 'ideal' address, we go with what the | |
39 | kernel provides (there is more likelihood that we will need to relocate | |
40 | on read in). */ | |
22a98240 IS |
41 | |
42 | #define PAGE_SZ 4096 | |
43 | #if defined(__x86_64) && defined(__LP64__) | |
44 | # define TRY_EMPTY_VM_SPACE 0x180000000000ULL | |
22a98240 IS |
45 | #elif defined(__x86_64) |
46 | # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL | |
22a98240 IS |
47 | #elif defined(__i386) |
48 | # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL | |
22a98240 IS |
49 | #elif defined(__POWERPC__) && defined(__LP64__) |
50 | # define TRY_EMPTY_VM_SPACE 0x180000000000ULL | |
22a98240 IS |
51 | #elif defined(__POWERPC__) |
52 | # define TRY_EMPTY_VM_SPACE 0x00006fe00000ULL | |
22a98240 IS |
53 | #elif defined(__aarch64__) |
54 | # undef PAGE_SZ | |
55 | # define PAGE_SZ 16384 | |
56 | # define TRY_EMPTY_VM_SPACE 0x180000000000ULL | |
22a98240 IS |
57 | #else |
58 | # error "unknown Darwin target" | |
59 | #endif | |
60 | ||
61 | /* Try to map a known position in the VM. The current PCH implementation | |
62 | can adjust values at write-time, but not at read-time thus we need to | |
63 | pick up the same position when reading as we got at write-time. */ | |
ed23bd30 GK |
64 | |
65 | void * | |
22a98240 | 66 | darwin_gt_pch_get_address (size_t sz, int fd) |
ed23bd30 | 67 | { |
0d5db1dd | 68 | /* First try with the constraint that we really want this address... */ |
22a98240 IS |
69 | void *addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, |
70 | MAP_PRIVATE | MAP_FIXED, fd, 0); | |
71 | ||
72 | if (addr != (void *) MAP_FAILED) | |
73 | munmap (addr, sz); | |
74 | ||
75 | /* This ought to be the only alternative to failure, but there are comments | |
76 | that suggest some versions of mmap can be buggy and return a different | |
77 | value. */ | |
78 | if (addr == (void *) TRY_EMPTY_VM_SPACE) | |
79 | return addr; | |
80 | ||
22a98240 IS |
81 | /* OK try to find a space without the constraint. */ |
82 | addr = mmap ((void *) TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, | |
83 | MAP_PRIVATE, fd, 0); | |
84 | ||
0d5db1dd IS |
85 | /* We return whatever the kernel gave us. */ |
86 | if (addr != (void *) MAP_FAILED) | |
22a98240 | 87 | { |
0d5db1dd IS |
88 | /* Unmap the area before returning. */ |
89 | munmap (addr, sz); | |
90 | return addr; | |
22a98240 IS |
91 | } |
92 | ||
0d5db1dd IS |
93 | /* Otherwise, try again but put some arbitrary buffer space first. */ |
94 | size_t buffer_size = 64 * 1024 * 1024; | |
22a98240 IS |
95 | void *buffer = mmap (0, buffer_size, PROT_NONE, |
96 | MAP_PRIVATE | MAP_ANON, -1, 0); | |
97 | addr = mmap ((void *)TRY_EMPTY_VM_SPACE, sz, PROT_READ | PROT_WRITE, | |
98 | MAP_PRIVATE, fd, 0); | |
0d5db1dd | 99 | |
22a98240 IS |
100 | if (buffer != (void *) MAP_FAILED) |
101 | munmap (buffer, buffer_size); | |
102 | ||
0d5db1dd IS |
103 | /* If we failed this time, that means there is *no* large enough free |
104 | space. */ | |
22a98240 IS |
105 | if (addr == (void *) MAP_FAILED) |
106 | { | |
34b45cc5 | 107 | error ("PCH memory is not available: %m"); |
22a98240 IS |
108 | return NULL; |
109 | } | |
110 | ||
22a98240 IS |
111 | munmap (addr, sz); |
112 | return addr; | |
ed23bd30 GK |
113 | } |
114 | ||
22a98240 IS |
115 | /* Try to mmap the PCH file at ADDR for SZ bytes at OFF offset in the file. |
116 | If we succeed return 1, if we cannot mmap the desired address, then we | |
117 | fail with -1. */ | |
ed23bd30 GK |
118 | |
119 | int | |
747380f4 | 120 | darwin_gt_pch_use_address (void *&addr, size_t sz, int fd, size_t off) |
ed23bd30 | 121 | { |
22a98240 IS |
122 | void *mapped_addr; |
123 | ||
124 | /* We're called with size == 0 if we're not planning to load a PCH | |
125 | file at all. This allows the hook to free any static space that | |
126 | we might have allocated at link time. */ | |
127 | if (sz == 0) | |
128 | return -1; | |
ed23bd30 | 129 | |
22a98240 | 130 | gcc_checking_assert (!(off % PAGE_SZ)); |
ed23bd30 | 131 | |
22a98240 IS |
132 | /* Try to map the file with MAP_PRIVATE and FIXED. */ |
133 | mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, | |
134 | MAP_PRIVATE | MAP_FIXED, fd, (off_t) off); | |
ed23bd30 | 135 | |
22a98240 IS |
136 | /* Hopefully, we succeed. */ |
137 | if (mapped_addr == addr) | |
138 | return 1; | |
ed23bd30 | 139 | |
0d5db1dd IS |
140 | /* In theory, the only alternative to success for MAP_FIXED should be FAILED |
141 | however, there are some buggy earlier implementations that could return | |
142 | an address. */ | |
22a98240 IS |
143 | if (mapped_addr != (void *) MAP_FAILED) |
144 | munmap (mapped_addr, sz); | |
145 | ||
0d5db1dd | 146 | /* Try to map the file with MAP_PRIVATE but let the kernel move it. */ |
22a98240 | 147 | mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, |
0d5db1dd | 148 | MAP_PRIVATE, fd, (off_t) off); |
22a98240 | 149 | |
0d5db1dd IS |
150 | /* Hopefully, we succeed. */ |
151 | if (mapped_addr != (void *) MAP_FAILED) | |
ed23bd30 | 152 | { |
0d5db1dd IS |
153 | addr = mapped_addr; |
154 | return 1; | |
22a98240 IS |
155 | } |
156 | ||
0d5db1dd IS |
157 | /* Try to make an anonymous private mmap at the desired location in case |
158 | the problem is in mapping the file. */ | |
159 | mapped_addr = mmap (addr, sz, PROT_READ | PROT_WRITE, | |
160 | MAP_PRIVATE | MAP_ANON, -1, (off_t)0); | |
161 | ||
162 | /* If this fails, we are out of ideas (and maybe memory). */ | |
163 | if (mapped_addr == (void *) MAP_FAILED) | |
164 | return -1; | |
165 | ||
166 | addr = mapped_addr; | |
167 | ||
22a98240 IS |
168 | if (lseek (fd, off, SEEK_SET) == (off_t) -1) |
169 | return -1; | |
ed23bd30 | 170 | |
22a98240 IS |
171 | while (sz) |
172 | { | |
173 | ssize_t nbytes; | |
ed23bd30 | 174 | |
bf15cd66 | 175 | nbytes = read (fd, mapped_addr, MIN (sz, (size_t) -1 >> 1)); |
22a98240 IS |
176 | if (nbytes <= 0) |
177 | return -1; | |
bf15cd66 | 178 | mapped_addr = (char *) mapped_addr + nbytes; |
22a98240 | 179 | sz -= nbytes; |
ed23bd30 GK |
180 | } |
181 | ||
22a98240 | 182 | return 1; |
ed23bd30 | 183 | } |