1dnl -*- Autoconf -*-
2dnl Copyright (C) 1993-2010, 2017-2018 Free Software Foundation, Inc.
3dnl This file is free software, distributed under the terms of the GNU
4dnl General Public License.  As a special exception to the GNU General
5dnl Public License, this file may be distributed as part of a program
6dnl that contains a configuration script generated by Autoconf, under
7dnl the same distribution terms as the rest of that program.
8
9dnl From Bruno Haible, Marcus Daniels, Sam Steingold.
10
11AC_PREREQ([2.57])
12
13AC_DEFUN([CL_MMAP],
14[
15  AC_BEFORE([$0], [CL_MUNMAP])
16  AC_BEFORE([$0], [CL_MPROTECT])
17  AC_CHECK_HEADER([sys/mman.h], [], [no_mmap=1])
18  if test -z "$no_mmap"; then
19    AC_CHECK_FUNC([mmap], [], [no_mmap=1])
20    if test -z "$no_mmap"; then
21      AC_DEFINE([HAVE_MMAP],,[have <sys/mmap.h> and the mmap() function])
22      dnl Test whether mmap with MAP_FIXED works.
23      dnl We cannot expect that it works at *all* addresses that we try,
24      dnl because every platform has a different address space layout.
25      dnl Therefore here we try whether it works at least for *some* addresses.
26      dnl The determination of the mmapable address ranges is done later.
27      AC_CACHE_CHECK([for mmap at fixed addresses], [cl_cv_func_mmap_fixed],
28        [mmap_prog_1='
29           #include <stdlib.h>
30           #ifdef HAVE_UNISTD_H
31            #include <unistd.h>
32           #endif
33           #include <fcntl.h>
34           #include <sys/types.h>
35           #include <sys/mman.h>
36           int main ()
37           {
38           '
39         mmap_prog_2='
40             {
41               unsigned long my_size = 32768; /* hope that 32768 is a multiple of the page size */
42               unsigned int successful_calls = 0;
43               unsigned long addr;
44               for (addr = 0x01230000UL;;)
45                 {
46                   if (mmap((void*)(addr & -my_size),my_size,PROT_READ|PROT_WRITE,flags|MAP_FIXED,fd,0) != (void*)-1)
47                     {
48                       /* Require at least 2 successful mmap calls.  This avoids
49                          spurious success on HP-UX IA-64 with 32-bit ABI. */
50                       if (++successful_calls >= 2)
51                         exit(0);
52                     }
53                   {
54                     unsigned long next_addr = (unsigned long)((double)addr * 1.94);
55                     if (next_addr <= addr) break;
56                     addr = next_addr;
57                   }
58                 }
59               exit(1);
60             }
61           }
62           '
63         succeeded=
64         AC_TRY_RUN(GL_NOCRASH[
65           $mmap_prog_1
66             int flags = MAP_ANON | MAP_PRIVATE;
67             int fd = -1;
68             nocrash_init();
69           $mmap_prog_2
70           ],
71           [succeeded="$succeeded"${succeeded:+,}"MAP_ANON"],
72           [],
73           [: # When cross-compiling, don't assume anything.])
74         AC_TRY_RUN(GL_NOCRASH[
75           $mmap_prog_1
76             int flags = MAP_ANONYMOUS | MAP_PRIVATE;
77             int fd = -1;
78             nocrash_init();
79           $mmap_prog_2
80           ],
81           [succeeded="$succeeded"${succeeded:+,}"MAP_ANONYMOUS"],
82           [],
83           [: # When cross-compiling, don't assume anything.])
84         AC_TRY_RUN(GL_NOCRASH[
85           $mmap_prog_1
86             #ifndef MAP_FILE
87              #define MAP_FILE 0
88             #endif
89             int flags = MAP_FILE | MAP_PRIVATE;
90             int fd = open("/dev/zero",O_RDONLY,0666);
91             if (fd<0) exit(1);
92             nocrash_init();
93           $mmap_prog_2
94           ],
95           [succeeded="$succeeded"${succeeded:+,}"/dev/zero"],
96           [],
97           [: # When cross-compiling, don't assume anything.])
98         if test -n "$succeeded"; then
99           cl_cv_func_mmap_fixed="yes ($succeeded)"
100         else
101           cl_cv_func_mmap_fixed=no
102         fi
103        ])
104      succeeded=`echo "$cl_cv_func_mmap_fixed" | LC_ALL=C tr '()' ',,'`
105      case "$succeeded" in
106        yes*,MAP_ANON,* )
107          AC_DEFINE([HAVE_MMAP_ANON],,[<sys/mman.h> defines MAP_ANON and mmaping with MAP_FIXED | MAP_ANON works])
108          ;;
109      esac
110      case "$succeeded" in
111        yes*,MAP_ANONYMOUS,* )
112          AC_DEFINE([HAVE_MMAP_ANONYMOUS],,[<sys/mman.h> defines MAP_ANONYMOUS and mmaping with MAP_FIXED | MAP_ANONYMOUS works])
113          ;;
114      esac
115      case "$succeeded" in
116        yes*,/dev/zero,* )
117          AC_DEFINE([HAVE_MMAP_DEVZERO],,[mmaping of the special device /dev/zero with MAP_FIXED works])
118          ;;
119      esac
120    fi
121  fi
122
123  case "$cl_cv_func_mmap_fixed" in
124    yes*)
125      dnl For SINGLEMAP_MEMORY and the TYPECODES object representation:
126      dnl Test which is the highest bit number < 63 (or < 31) at which the kernel
127      dnl allows us to mmap memory with MAP_FIXED. That is, try
128      dnl   0x4000000000000000 -> 62
129      dnl   0x2000000000000000 -> 61
130      dnl   0x1000000000000000 -> 60
131      dnl   ...
132      dnl and return the highest bit number for which mmap succeeds.
133      dnl Don't need to test bit 63 (or 31) because we use it as garcol_bit in TYPECODES.
134      AC_CACHE_CHECK([for highest bit number which can be included in mmaped addresses],
135        [cl_cv_func_mmap_highest_bit],
136        [AC_TRY_RUN([
137           #include <stdlib.h>
138           #ifdef HAVE_UNISTD_H
139            #include <unistd.h>
140           #endif
141           #include <fcntl.h>
142           #include <sys/types.h>
143           #include <sys/mman.h>
144           #ifndef MAP_FILE
145            #define MAP_FILE 0
146           #endif
147           #ifndef MAP_VARIABLE
148            #define MAP_VARIABLE 0
149           #endif
150           int
151           main ()
152           {
153             unsigned int my_size = 32768; /* hope that 32768 is a multiple of the page size */
154             int pos;
155             for (pos = 8*sizeof(void*)-2; pos > 0; pos--)
156               {
157                 unsigned long address = (unsigned long)1 << pos;
158                 if (address < 4096)
159                   break;
160                 #ifdef __ia64__
161                 /* On IA64 in 64-bit mode, the executable sits at 0x4000000000000000.
162                    An mmap call to this address would either crash the program (on Linux)
163                    or fail (on HP-UX). */
164                 if (pos == 62)
165                   continue;
166                 #endif
167                 #ifdef __arm__
168                 /* On Linux/arm64 with CC="arm-linux-gnueabihf-gcc-4.8",
169                    some shared libraries may sit at 0x40000000. An mmap call to
170                    this address may crash the program. */
171                 if (pos == 30)
172                   address += 0x01000000UL;
173                 #endif
174                 #ifdef __riscv
175                 /* On Linux/riscv64, the ld.so and some shared libraries may
176                    sit at 0x2000000000. An mmap call to this address may
177                    crash the program. */
178                 if (pos == 37)
179                   address += 0x01000000UL;
180                 #endif
181                 {
182                   char *p;
183                   #if defined HAVE_MMAP_ANON
184                     p = (char *) mmap ((void*)address, my_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_VARIABLE, -1, 0);
185                   #elif defined HAVE_MMAP_ANONYMOUS
186                     p = (char *) mmap ((void*)address, my_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_VARIABLE, -1, 0);
187                   #elif defined HAVE_MMAP_DEVZERO
188                     int zero_fd = open("/dev/zero", O_RDONLY, 0666);
189                     if (zero_fd < 0)
190                       return 1;
191                     p = (char *) mmap ((void*)address, my_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_FILE | MAP_VARIABLE, zero_fd, 0);
192                   #else
193                     ??
194                   #endif
195                   if (p != (char*) -1)
196                     /* mmap succeeded. */
197                     return pos;
198                 }
199               }
200             return 0;
201           }
202           ],
203           [cl_cv_func_mmap_highest_bit=none],
204           [cl_cv_func_mmap_highest_bit=$?
205            case "$cl_cv_func_mmap_highest_bit" in
206              0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 ) dnl Most likely a compiler error code.
207                cl_cv_func_mmap_highest_bit=none ;;
208            esac
209           ],
210           [cl_cv_func_mmap_highest_bit="guessing none"])
211        ])
212      case "$cl_cv_func_mmap_highest_bit" in
213        *none) value='-1' ;;
214        *) value="$cl_cv_func_mmap_highest_bit" ;;
215      esac
216      ;;
217    *)
218      value='-1'
219      ;;
220  esac
221  AC_DEFINE_UNQUOTED([MMAP_FIXED_ADDRESS_HIGHEST_BIT], [$value],
222    [Define to the highest bit number that can be included in mmaped addresses.])
223])
224