ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.6
Committed: 2009-11-13T01:57:48Z (15 years ago) by asvitkine
Content type: text/plain
Branch: MAIN
Changes since 1.5: +138 -47 lines
Log Message:
[ Patch from Jean-Pierre <chombier@free.fr> ]
Make lowmem be able to deal with x86_64 binaries.

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 /*
110     * 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 gbeauche 1.1
139     if (argc != 2) {
140     (void)fprintf(stderr, "Usage: %s executable\n", progname);
141     exit(1);
142     }
143    
144 asvitkine 1.6 filename = argv[1];
145    
146     fd = open(filename, O_RDWR, 0);
147 gbeauche 1.1 if (fd == -1) {
148     (void)fprintf(stderr, "%s: could not open %s: %s\n",
149 asvitkine 1.6 progname, filename, strerror(errno));
150 gbeauche 1.1 exit(1);
151     }
152    
153 asvitkine 1.6 file_size = lseek(fd, 0, SEEK_END);
154     if (file_size == -1) {
155     // for some mysterious reason, this sometimes fails...
156     file_size = 0x1000;
157     #if 0
158     (void)fprintf(stderr, "%s: could not get size of %s: %s\n",
159     progname, filename, strerror(errno));
160     exit(1);
161     #endif
162     }
163    
164 gbeauche 1.1 /*
165     * Size does not really matter, it will be rounded-up to a multiple
166     * of the page size automatically.
167     */
168 asvitkine 1.6 addr = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
169 gbeauche 1.1 MAP_FILE | MAP_SHARED, fd, 0);
170     if (addr == NULL) {
171     (void)fprintf(stderr, "%s: could not mmap %s: %s\n",
172 asvitkine 1.6 progname, filename, strerror(errno));
173 gbeauche 1.1 exit(1);
174     }
175    
176     /*
177     * Check to see if the Mach-O magic bytes are in the header.
178     */
179     machhead = (void *)addr;
180 asvitkine 1.6 #if defined(MH_MAGIC_64)
181     machhead64 = (void *)addr;
182     #endif
183     fathead = (void *)addr;
184    
185     #if defined(MH_MAGIC_64)
186     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM || machhead64->magic == MH_CIGAM_64;
187     #else
188     do_swap = machhead->magic == MH_CIGAM || fathead->magic == FAT_CIGAM;
189     #endif
190    
191     if (target_uint32(machhead->magic) == MH_MAGIC) {
192     pagezero_32(machhead);
193     #if defined(MH_MAGIC_64)
194     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
195     pagezero_64(machhead64);
196     #endif
197     } else if (target_uint32(fathead->magic) == FAT_MAGIC) {
198     struct fat_arch *arch = (void *)&fathead[1];
199     int saved_swap = do_swap;
200     int i;
201     for (i = 0; i < target_uint32(fathead->nfat_arch); ++i, ++arch) {
202     machhead = (void *)(addr + target_uint32(arch->offset));
203     #if defined(MH_MAGIC_64)
204     machhead64 = (void *)(addr + target_uint32(arch->offset));
205     #endif
206     #if defined(MH_MAGIC_64)
207     do_swap = machhead->magic == MH_CIGAM || machhead64->magic == MH_CIGAM_64;
208     #else
209     do_swap = machhead->magic == MH_CIGAM;
210     #endif
211     if (target_uint32(machhead->magic) == MH_MAGIC) {
212     pagezero_32(machhead);
213     #if defined(MH_MAGIC_64)
214     } else if (target_uint32(machhead64->magic) == MH_MAGIC_64) {
215     pagezero_64(machhead64);
216     #endif
217     } else {
218     (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
219     progname, filename);
220     exit(1);
221     }
222     do_swap = saved_swap;
223     }
224     } else {
225 gbeauche 1.1 (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
226 asvitkine 1.6 progname, filename);
227 gbeauche 1.1 exit(1);
228     }
229    
230     /*
231     * We do not make __PAGEZERO 8K in this program because then
232     * all of the offsets would be wrong in the object file after
233     * this segment. Instead we use the -pagezero_size option
234     * to link the executable.
235     */
236 asvitkine 1.6 if (msync(addr, file_size, MS_SYNC) == -1) {
237 gbeauche 1.1 (void)fprintf(stderr, "%s: could not sync %s: %s\n",
238 asvitkine 1.6 progname, filename, strerror(errno));
239 gbeauche 1.1 exit(1);
240     }
241    
242 asvitkine 1.6 if (munmap(addr, file_size) == -1) {
243 gbeauche 1.1 (void)fprintf(stderr, "%s: could not unmap %s: %s\n",
244 asvitkine 1.6 progname, filename, strerror(errno));
245 gbeauche 1.1 exit(1);
246     }
247    
248     (void)close(fd);
249    
250     exit(0);
251     }