]>
Commit | Line | Data |
---|---|---|
90aa6719 | 1 | /* mingw32 host-specific hook definitions. |
83ffe9cd | 2 | Copyright (C) 2004-2023 Free Software Foundation, Inc. |
90aa6719 DS |
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 |
90aa6719 DS |
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/>. */ | |
90aa6719 | 19 | |
8fcc61f8 RS |
20 | #define IN_TARGET_CODE 1 |
21 | ||
90aa6719 DS |
22 | #include "config.h" |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
e11c4407 | 25 | #include "diagnostic.h" |
90aa6719 DS |
26 | #include "hosthooks.h" |
27 | #include "hosthooks-def.h" | |
90aa6719 DS |
28 | |
29 | ||
30 | #define WIN32_LEAN_AND_MEAN /* Not so important if we have windows.h.gch. */ | |
31 | #include <windows.h> | |
e7b0b62d | 32 | #include <stdlib.h> |
90aa6719 DS |
33 | |
34 | static void * mingw32_gt_pch_get_address (size_t, int); | |
747380f4 | 35 | static int mingw32_gt_pch_use_address (void *&, size_t, int, size_t); |
90aa6719 DS |
36 | static size_t mingw32_gt_pch_alloc_granularity (void); |
37 | ||
38 | #undef HOST_HOOKS_GT_PCH_GET_ADDRESS | |
39 | #define HOST_HOOKS_GT_PCH_GET_ADDRESS mingw32_gt_pch_get_address | |
40 | #undef HOST_HOOKS_GT_PCH_USE_ADDRESS | |
41 | #define HOST_HOOKS_GT_PCH_USE_ADDRESS mingw32_gt_pch_use_address | |
42 | #undef HOST_HOOKS_GT_PCH_ALLOC_GRANULARITY | |
43 | #define HOST_HOOKS_GT_PCH_ALLOC_GRANULARITY mingw32_gt_pch_alloc_granularity | |
44 | ||
45 | static inline void w32_error(const char*, const char*, int, const char*); | |
46 | ||
47 | /* FIXME: Is this big enough? */ | |
48 | static const size_t pch_VA_max_size = 128 * 1024 * 1024; | |
49 | ||
50 | /* Granularity for reserving address space. */ | |
e7b0b62d | 51 | static size_t va_granularity = 0x10000; |
90aa6719 DS |
52 | |
53 | /* Print out the GetLastError() translation. */ | |
54 | static inline void | |
55 | w32_error (const char* function, const char* file, int line, | |
56 | const char* my_msg) | |
57 | { | |
58 | LPSTR w32_msgbuf; | |
59 | FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | |
60 | | FORMAT_MESSAGE_FROM_SYSTEM | |
61 | | FORMAT_MESSAGE_IGNORE_INSERTS | |
62 | | FORMAT_MESSAGE_MAX_WIDTH_MASK, | |
63 | NULL, GetLastError(), | |
64 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
65 | (LPSTR) &w32_msgbuf, 0, NULL); | |
66 | fprintf(stderr, "internal error in %s, at %s:%d: %s: %s\n", | |
67 | function, trim_filename (file), line, my_msg, w32_msgbuf); | |
68 | LocalFree ((HLOCAL)w32_msgbuf); | |
69 | } | |
70 | ||
71 | /* Granularity for reserving address space. */ | |
e7b0b62d KT |
72 | static size_t |
73 | mingw32_gt_pch_alloc_granularity (void) | |
90aa6719 | 74 | { |
e7b0b62d KT |
75 | SYSTEM_INFO si; |
76 | ||
77 | GetSystemInfo (&si); | |
78 | va_granularity = (size_t) si.dwAllocationGranularity; | |
79 | ||
90aa6719 DS |
80 | return va_granularity; |
81 | } | |
82 | ||
83 | /* Identify an address that's likely to be free in a subsequent invocation | |
84 | of the compiler. The area should be able to hold SIZE bytes. FD is an | |
85 | open file descriptor if the host would like to probe with mmap. */ | |
86 | ||
87 | static void * | |
997ef9e7 | 88 | mingw32_gt_pch_get_address (size_t size, int) |
90aa6719 DS |
89 | { |
90 | void* res; | |
91 | size = (size + va_granularity - 1) & ~(va_granularity - 1); | |
92 | if (size > pch_VA_max_size) | |
93 | return NULL; | |
94 | ||
95 | /* FIXME: We let system determine base by setting first arg to NULL. | |
96 | Allocating at top of available address space avoids unnecessary | |
b8a10943 CW |
97 | fragmentation of "ordinary" (malloc's) address space but may not |
98 | be safe with delayed load of system dll's. Preferred addresses | |
99 | for NT system dlls is in 0x70000000 to 0x78000000 range. | |
100 | If we allocate at bottom we need to reserve the address as early | |
101 | as possible and at the same point in each invocation. */ | |
90aa6719 DS |
102 | |
103 | res = VirtualAlloc (NULL, pch_VA_max_size, | |
104 | MEM_RESERVE | MEM_TOP_DOWN, | |
105 | PAGE_NOACCESS); | |
106 | if (!res) | |
107 | w32_error (__FUNCTION__, __FILE__, __LINE__, "VirtualAlloc"); | |
108 | else | |
109 | /* We do not need the address space for now, so free it. */ | |
110 | VirtualFree (res, 0, MEM_RELEASE); | |
111 | ||
112 | return res; | |
113 | } | |
114 | ||
115 | /* ADDR is an address returned by gt_pch_get_address. Attempt to allocate | |
116 | SIZE bytes at the same address and load it with the data from FD at | |
117 | OFFSET. Return -1 if we couldn't allocate memory at ADDR, return 0 | |
118 | if the memory is allocated but the data not loaded, return 1 if done. */ | |
119 | ||
120 | static int | |
747380f4 | 121 | mingw32_gt_pch_use_address (void *&addr, size_t size, int fd, |
90aa6719 DS |
122 | size_t offset) |
123 | { | |
124 | void * mmap_addr; | |
b8a10943 | 125 | HANDLE mmap_handle; |
e7b0b62d | 126 | |
b8a10943 CW |
127 | /* Apparently, MS Vista puts unnamed file mapping objects into Global |
128 | namespace when running an application in a Terminal Server | |
129 | session. This causes failure since, by default, applications | |
130 | don't get SeCreateGlobalPrivilege. We don't need global | |
73d21f56 KT |
131 | memory sharing so explicitly put object into Local namespace. |
132 | ||
8e481a2c DS |
133 | If multiple concurrent GCC processes are using PCH functionality, |
134 | MapViewOfFileEx returns "Access Denied" error. So we ensure the | |
135 | session-wide mapping name is unique by appending process ID. */ | |
73d21f56 | 136 | |
8e481a2c | 137 | #define OBJECT_NAME_FMT "Local\\MinGWGCCPCH-" |
b8a10943 | 138 | |
8e481a2c | 139 | char* object_name = NULL; |
b8a10943 CW |
140 | /* However, the documentation for CreateFileMapping says that on NT4 |
141 | and earlier, backslashes are invalid in object name. So, we need | |
142 | to check if we are on Windows2000 or higher. */ | |
143 | OSVERSIONINFO version_info; | |
e7b0b62d KT |
144 | int r; |
145 | ||
8e481a2c DS |
146 | version_info.dwOSVersionInfoSize = sizeof (version_info); |
147 | ||
b8a10943 CW |
148 | if (size == 0) |
149 | return 0; | |
150 | ||
90aa6719 DS |
151 | /* Offset must be also be a multiple of allocation granularity for |
152 | this to work. We can't change the offset. */ | |
153 | if ((offset & (va_granularity - 1)) != 0 || size > pch_VA_max_size) | |
154 | return -1; | |
155 | ||
b8a10943 | 156 | |
8e481a2c DS |
157 | /* Determine the version of Windows we are running on and use a |
158 | uniquely-named local object if running > 4. */ | |
159 | GetVersionEx (&version_info); | |
22dfc3e8 ML |
160 | |
161 | char local_object_name[sizeof (OBJECT_NAME_FMT) + sizeof (DWORD) * 2]; | |
8e481a2c DS |
162 | if (version_info.dwMajorVersion > 4) |
163 | { | |
8e481a2c DS |
164 | snprintf (local_object_name, sizeof (local_object_name), |
165 | OBJECT_NAME_FMT "%lx", GetCurrentProcessId()); | |
166 | object_name = local_object_name; | |
167 | } | |
b8a10943 CW |
168 | mmap_handle = CreateFileMappingA ((HANDLE) _get_osfhandle (fd), NULL, |
169 | PAGE_WRITECOPY | SEC_COMMIT, 0, 0, | |
8e481a2c DS |
170 | object_name); |
171 | ||
90aa6719 DS |
172 | if (mmap_handle == NULL) |
173 | { | |
174 | w32_error (__FUNCTION__, __FILE__, __LINE__, "CreateFileMapping"); | |
175 | return -1; | |
176 | } | |
e7b0b62d KT |
177 | |
178 | /* Retry five times, as here might occure a race with multiple gcc's | |
179 | instances at same time. */ | |
180 | for (r = 0; r < 5; r++) | |
181 | { | |
182 | mmap_addr = MapViewOfFileEx (mmap_handle, FILE_MAP_COPY, 0, offset, | |
183 | size, addr); | |
184 | if (mmap_addr == addr) | |
185 | break; | |
186 | if (r != 4) | |
187 | Sleep (500); | |
188 | } | |
189 | ||
90aa6719 DS |
190 | if (mmap_addr != addr) |
191 | { | |
192 | w32_error (__FUNCTION__, __FILE__, __LINE__, "MapViewOfFileEx"); | |
193 | CloseHandle(mmap_handle); | |
194 | return -1; | |
195 | } | |
196 | ||
197 | return 1; | |
198 | } | |
199 | ||
200 | const struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER; |