ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.8
Committed: 2011-12-27T20:50:27Z (12 years, 8 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
Changes since 1.7: +1 -1 lines
Log Message:
check for MAP_FAILED result

File Contents

# User Rev Content
1 gbeauche 1.1 /*
2     * lowmem.c - enable access to low memory globals on Darwin
3     *
4     * Copyright (c) 2003 Michael Z. Sliczniak
5     *
6 gbeauche 1.3 * Basilisk II (C) 1997-2005 Christian Bauer
7 gbeauche 1.1 *
8     * This program is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation; either version 2 of the License, or
11     * (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21     */
22    
23     #include <sys/types.h>
24     #include <sys/mman.h>
25     #include <fcntl.h>
26     #include <errno.h>
27     #include <stdio.h>
28 asvitkine 1.4 #include <stdlib.h>
29 gbeauche 1.1 #include <string.h>
30     #include <mach/vm_prot.h>
31     #include <mach-o/loader.h>
32 asvitkine 1.6 #include <mach-o/fat.h>
33 gbeauche 1.1
34     static const char progname[] = "lowmem";
35 asvitkine 1.6 static const char *filename;
36 gbeauche 1.1
37 gbeauche 1.5 static int do_swap = 0;
38    
39     static uint32_t target_uint32(uint32_t value)
40     {
41     if (do_swap)
42 asvitkine 1.6 value = OSSwapInt32(value);
43 gbeauche 1.5 return value;
44     }
45    
46 asvitkine 1.6 void pagezero_32(struct mach_header *machhead)
47     {
48     struct segment_command *sc_cmd;
49    
50     if (target_uint32(machhead->filetype) != MH_EXECUTE) {
51     (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
52     progname, filename);
53     exit(1);
54     }
55     if (machhead->ncmds == 0) {
56     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
57     progname, filename);
58     exit(1);
59     }
60     sc_cmd = (void *)&machhead[1];
61     if (target_uint32(sc_cmd->cmd) != LC_SEGMENT){
62     (void)fprintf(stderr, "%s: load segment not first command in %s\n",
63     progname, filename);
64     exit(1);
65     }
66     if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof (*sc_cmd->segname))) {
67     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
68     progname, filename);
69     exit(1);
70     }
71     /* change the permissions */
72     sc_cmd->maxprot = target_uint32(VM_PROT_ALL);
73     sc_cmd->initprot = target_uint32(VM_PROT_ALL);
74     }
75    
76     #if defined(MH_MAGIC_64)
77     void pagezero_64(struct mach_header_64 *machhead)
78     {
79     struct segment_command_64 *sc_cmd;
80    
81     if (target_uint32(machhead->filetype) != MH_EXECUTE) {
82     (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
83     progname, filename);
84     exit(1);
85     }
86     if (machhead->ncmds == 0) {
87     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
88     progname, filename);
89     exit(1);
90     }
91     sc_cmd = (void *)&machhead[1];
92     if (target_uint32(sc_cmd->cmd) != LC_SEGMENT_64) {
93     (void)fprintf(stderr, "%s: load segment not first command in %s\n",
94     progname, filename);
95     exit(1);
96     }
97     if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof(*sc_cmd->segname))) {
98     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
99     progname, filename);
100     exit(1);
101     }
102     /* change the permissions */
103     sc_cmd->maxprot = target_uint32(VM_PROT_ALL);
104     sc_cmd->initprot = target_uint32(VM_PROT_ALL);
105     }
106     #endif
107    
108     /*
109 gbeauche 1.1 * Under Mach there is very little assumed about the memory map of object
110     * files. It is the job of the loader to create the initial memory map of an
111     * executable. In a Mach-O executable there will be numerous loader commands
112     * that the loader must process. Some of these will create the initial memory
113     * map used by the executable. Under Darwin the static object file linker,
114     * ld, automatically adds the __PAGEZERO segment to all executables. The
115     * default size of this segment is the page size of the target system and
116     * the initial and maximum permissions are set to allow no access. This is so
117     * that all programs fault on a NULL pointer dereference. Arguably this is
118     * incorrect and the maximum permissions shoould be rwx so that programs can
119     * change this default behavior. Then programs could be written that assume
120     * a null string at the null address, which was the convention on some
121     * systems. In our case we need to have 8K mapped at zero for the low memory
122     * globals and this program modifies the segment load command in the
123     * basiliskII executable so that it can be used for data.
124     */
125    
126     int
127     main(int argc, const char *argv[])
128     {
129     int fd;
130     char *addr;
131 asvitkine 1.6 off_t file_size;
132 gbeauche 1.1 struct mach_header *machhead;
133 asvitkine 1.6 #if defined(MH_MAGIC_64)
134     struct mach_header_64 *machhead64;
135     #endif
136     struct fat_header *fathead;
137 gbeauche 1.1
138     if (argc != 2) {
139     (void)fprintf(stderr, "Usage: %s executable\n", progname);
140     exit(1);
141     }
142    
143 asvitkine 1.6 filename = argv[1];
144    
145     fd = open(filename, O_RDWR, 0);
146 gbeauche 1.1 if (fd == -1) {
147     (void)fprintf(stderr, "%s: could not open %s: %s\n",
148 asvitkine 1.6 progname, filename, strerror(errno));
149 gbeauche 1.1 exit(1);
150     }
151    
152 asvitkine 1.6 file_size = lseek(fd, 0, SEEK_END);
153     if (file_size == -1) {
154     // for some mysterious reason, this sometimes fails...
155     file_size = 0x1000;
156     #if 0
157     (void)fprintf(stderr, "%s: could not get size of %s: %s\n",
158     progname, filename, strerror(errno));
159     exit(1);
160     #endif
161     }
162    
163 gbeauche 1.1 /*
164     * Size does not really matter, it will be rounded-up to a multiple
165     * of the page size automatically.
166     */
167 asvitkine 1.6 addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
168 gbeauche 1.1 MAP_FILE | MAP_SHARED, fd, 0);
169 asvitkine 1.8 if (addr == NULL || addr == MAP_FAILED) {
170 gbeauche 1.1 (void)fprintf(stderr, "%s: could not mmap %s: %s\n",
171 asvitkine 1.6 progname, filename, strerror(errno));
172 gbeauche 1.1 exit(1);
173     }
174    
175     /*
176     * Check to see if the Mach-O magic bytes are in the header.
177     */
178     machhead = (void *)addr;
179 asvitkine 1.6 #if defined(MH_MAGIC_64)
180     machhead64 = (void *)addr;
181     #endif
182     fathead = (void *)addr;
183    
184     #if defined(MH_MAGIC_64)
185     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM || machhead64->magic == MH_CIGAM_64;
186     #else
187     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM;
188     #endif
189    
190     if (target_uint32(machhead->magic) == MH_MAGIC) {
191     pagezero_32(machhead);
192     #if defined(MH_MAGIC_64)
193     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
194     pagezero_64(machhead64);
195     #endif
196     } else if (target_uint32(fathead->magic) == FAT_MAGIC) {
197     struct fat_arch *arch = (void *)&fathead[1];
198     int saved_swap = do_swap;
199     int i;
200     for (i = 0; i < target_uint32(fathead->nfat_arch); ++i, ++arch) {
201     machhead = (void *)(addr + target_uint32(arch->offset));
202     #if defined(MH_MAGIC_64)
203     machhead64 = (void *)(addr + target_uint32(arch->offset));
204     #endif
205     #if defined(MH_MAGIC_64)
206     do_swap = machhead->magic == MH_CIGAM || machhead64->magic == MH_CIGAM_64;
207     #else
208     do_swap = machhead->magic == MH_CIGAM;
209     #endif
210     if (target_uint32(machhead->magic) == MH_MAGIC) {
211     pagezero_32(machhead);
212     #if defined(MH_MAGIC_64)
213     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
214     pagezero_64(machhead64);
215     #endif
216     } else {
217     (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
218     progname, filename);
219     exit(1);
220     }
221     do_swap = saved_swap;
222     }
223     } else {
224 gbeauche 1.1 (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
225 asvitkine 1.6 progname, filename);
226 gbeauche 1.1 exit(1);
227     }
228    
229     /*
230     * We do not make __PAGEZERO 8K in this program because then
231     * all of the offsets would be wrong in the object file after
232     * this segment. Instead we use the -pagezero_size option
233     * to link the executable.
234     */
235 asvitkine 1.6 if (msync(addr, file_size, MS_SYNC) == -1) {
236 gbeauche 1.1 (void)fprintf(stderr, "%s: could not sync %s: %s\n",
237 asvitkine 1.6 progname, filename, strerror(errno));
238 gbeauche 1.1 exit(1);
239     }
240    
241 asvitkine 1.6 if (munmap(addr, file_size) == -1) {
242 gbeauche 1.1 (void)fprintf(stderr, "%s: could not unmap %s: %s\n",
243 asvitkine 1.6 progname, filename, strerror(errno));
244 gbeauche 1.1 exit(1);
245     }
246    
247     (void)close(fd);
248    
249     exit(0);
250     }