ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.9
Committed: 2011-12-27T21:01:32Z (12 years, 11 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +9 -11 lines
Log Message:
get file size using stat, which seems to be more reliable

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 asvitkine 1.9 #include <sys/stat.h>
34 gbeauche 1.1
35     static const char progname[] = "lowmem";
36 asvitkine 1.6 static const char *filename;
37 gbeauche 1.1
38 gbeauche 1.5 static int do_swap = 0;
39    
40     static uint32_t target_uint32(uint32_t value)
41     {
42     if (do_swap)
43 asvitkine 1.6 value = OSSwapInt32(value);
44 gbeauche 1.5 return value;
45     }
46    
47 asvitkine 1.6 void pagezero_32(struct mach_header *machhead)
48     {
49     struct segment_command *sc_cmd;
50    
51     if (target_uint32(machhead->filetype) != MH_EXECUTE) {
52     (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
53     progname, filename);
54     exit(1);
55     }
56     if (machhead->ncmds == 0) {
57     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
58     progname, filename);
59     exit(1);
60     }
61     sc_cmd = (void *)&machhead[1];
62     if (target_uint32(sc_cmd->cmd) != LC_SEGMENT){
63     (void)fprintf(stderr, "%s: load segment not first command in %s\n",
64     progname, filename);
65     exit(1);
66     }
67     if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof (*sc_cmd->segname))) {
68     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
69     progname, filename);
70     exit(1);
71     }
72     /* change the permissions */
73     sc_cmd->maxprot = target_uint32(VM_PROT_ALL);
74     sc_cmd->initprot = target_uint32(VM_PROT_ALL);
75     }
76    
77     #if defined(MH_MAGIC_64)
78     void pagezero_64(struct mach_header_64 *machhead)
79     {
80     struct segment_command_64 *sc_cmd;
81    
82     if (target_uint32(machhead->filetype) != MH_EXECUTE) {
83     (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
84     progname, filename);
85     exit(1);
86     }
87     if (machhead->ncmds == 0) {
88     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
89     progname, filename);
90     exit(1);
91     }
92     sc_cmd = (void *)&machhead[1];
93     if (target_uint32(sc_cmd->cmd) != LC_SEGMENT_64) {
94     (void)fprintf(stderr, "%s: load segment not first command in %s\n",
95     progname, filename);
96     exit(1);
97     }
98     if (strncmp(sc_cmd->segname, "__PAGEZERO", sizeof(*sc_cmd->segname))) {
99     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
100     progname, filename);
101     exit(1);
102     }
103     /* change the permissions */
104     sc_cmd->maxprot = target_uint32(VM_PROT_ALL);
105     sc_cmd->initprot = target_uint32(VM_PROT_ALL);
106     }
107     #endif
108    
109     /*
110 gbeauche 1.1 * Under Mach there is very little assumed about the memory map of object
111     * files. It is the job of the loader to create the initial memory map of an
112     * executable. In a Mach-O executable there will be numerous loader commands
113     * that the loader must process. Some of these will create the initial memory
114     * map used by the executable. Under Darwin the static object file linker,
115     * ld, automatically adds the __PAGEZERO segment to all executables. The
116     * default size of this segment is the page size of the target system and
117     * the initial and maximum permissions are set to allow no access. This is so
118     * that all programs fault on a NULL pointer dereference. Arguably this is
119     * incorrect and the maximum permissions shoould be rwx so that programs can
120     * change this default behavior. Then programs could be written that assume
121     * a null string at the null address, which was the convention on some
122     * systems. In our case we need to have 8K mapped at zero for the low memory
123     * globals and this program modifies the segment load command in the
124     * basiliskII executable so that it can be used for data.
125     */
126    
127     int
128     main(int argc, const char *argv[])
129     {
130     int fd;
131     char *addr;
132 asvitkine 1.6 off_t file_size;
133 gbeauche 1.1 struct mach_header *machhead;
134 asvitkine 1.6 #if defined(MH_MAGIC_64)
135     struct mach_header_64 *machhead64;
136     #endif
137     struct fat_header *fathead;
138 asvitkine 1.9 struct stat f;
139 gbeauche 1.1
140     if (argc != 2) {
141     (void)fprintf(stderr, "Usage: %s executable\n", progname);
142     exit(1);
143     }
144    
145 asvitkine 1.6 filename = argv[1];
146    
147 asvitkine 1.9 if (stat(filename, &f)) {
148     (void)fprintf(stderr, "%s: could not stat %s: %s\n",
149     progname, filename, strerror(errno));
150     exit(1);
151     }
152     file_size = f.st_size;
153    
154 asvitkine 1.6 fd = open(filename, O_RDWR, 0);
155 gbeauche 1.1 if (fd == -1) {
156     (void)fprintf(stderr, "%s: could not open %s: %s\n",
157 asvitkine 1.6 progname, filename, strerror(errno));
158 gbeauche 1.1 exit(1);
159     }
160    
161     /*
162     * Size does not really matter, it will be rounded-up to a multiple
163     * of the page size automatically.
164     */
165 asvitkine 1.6 addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
166 gbeauche 1.1 MAP_FILE | MAP_SHARED, fd, 0);
167 asvitkine 1.8 if (addr == NULL || addr == MAP_FAILED) {
168 gbeauche 1.1 (void)fprintf(stderr, "%s: could not mmap %s: %s\n",
169 asvitkine 1.6 progname, filename, strerror(errno));
170 gbeauche 1.1 exit(1);
171     }
172    
173     /*
174     * Check to see if the Mach-O magic bytes are in the header.
175     */
176     machhead = (void *)addr;
177 asvitkine 1.6 #if defined(MH_MAGIC_64)
178     machhead64 = (void *)addr;
179     #endif
180     fathead = (void *)addr;
181    
182     #if defined(MH_MAGIC_64)
183     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM || machhead64->magic == MH_CIGAM_64;
184     #else
185     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM;
186     #endif
187    
188     if (target_uint32(machhead->magic) == MH_MAGIC) {
189     pagezero_32(machhead);
190     #if defined(MH_MAGIC_64)
191     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
192     pagezero_64(machhead64);
193     #endif
194     } else if (target_uint32(fathead->magic) == FAT_MAGIC) {
195     struct fat_arch *arch = (void *)&fathead[1];
196     int saved_swap = do_swap;
197     int i;
198     for (i = 0; i < target_uint32(fathead->nfat_arch); ++i, ++arch) {
199     machhead = (void *)(addr + target_uint32(arch->offset));
200     #if defined(MH_MAGIC_64)
201     machhead64 = (void *)(addr + target_uint32(arch->offset));
202     #endif
203     #if defined(MH_MAGIC_64)
204     do_swap = machhead->magic == MH_CIGAM || machhead64->magic == MH_CIGAM_64;
205     #else
206     do_swap = machhead->magic == MH_CIGAM;
207     #endif
208     if (target_uint32(machhead->magic) == MH_MAGIC) {
209     pagezero_32(machhead);
210     #if defined(MH_MAGIC_64)
211     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
212     pagezero_64(machhead64);
213     #endif
214     } else {
215     (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
216     progname, filename);
217     exit(1);
218     }
219     do_swap = saved_swap;
220     }
221     } else {
222 gbeauche 1.1 (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
223 asvitkine 1.6 progname, filename);
224 gbeauche 1.1 exit(1);
225     }
226    
227     /*
228     * We do not make __PAGEZERO 8K in this program because then
229     * all of the offsets would be wrong in the object file after
230     * this segment. Instead we use the -pagezero_size option
231     * to link the executable.
232     */
233 asvitkine 1.6 if (msync(addr, file_size, MS_SYNC) == -1) {
234 gbeauche 1.1 (void)fprintf(stderr, "%s: could not sync %s: %s\n",
235 asvitkine 1.6 progname, filename, strerror(errno));
236 gbeauche 1.1 exit(1);
237     }
238    
239 asvitkine 1.6 if (munmap(addr, file_size) == -1) {
240 gbeauche 1.1 (void)fprintf(stderr, "%s: could not unmap %s: %s\n",
241 asvitkine 1.6 progname, filename, strerror(errno));
242 gbeauche 1.1 exit(1);
243     }
244    
245     (void)close(fd);
246    
247     exit(0);
248     }