ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.2
Committed: 2004-01-12T15:54:42Z (20 years, 8 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
Happy New Year!

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 cebix 1.2 * Basilisk II (C) 1997-2004 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     #include <string.h>
29     #include <mach/vm_prot.h>
30     #include <mach-o/loader.h>
31    
32     static const char progname[] = "lowmem";
33    
34     /*
35     * Under Mach there is very little assumed about the memory map of object
36     * files. It is the job of the loader to create the initial memory map of an
37     * executable. In a Mach-O executable there will be numerous loader commands
38     * that the loader must process. Some of these will create the initial memory
39     * map used by the executable. Under Darwin the static object file linker,
40     * ld, automatically adds the __PAGEZERO segment to all executables. The
41     * default size of this segment is the page size of the target system and
42     * the initial and maximum permissions are set to allow no access. This is so
43     * that all programs fault on a NULL pointer dereference. Arguably this is
44     * incorrect and the maximum permissions shoould be rwx so that programs can
45     * change this default behavior. Then programs could be written that assume
46     * a null string at the null address, which was the convention on some
47     * systems. In our case we need to have 8K mapped at zero for the low memory
48     * globals and this program modifies the segment load command in the
49     * basiliskII executable so that it can be used for data.
50     */
51    
52     int
53     main(int argc, const char *argv[])
54     {
55     int fd;
56     char *addr;
57     struct mach_header *machhead;
58     struct segment_command *sc_cmd;
59    
60     if (argc != 2) {
61     (void)fprintf(stderr, "Usage: %s executable\n", progname);
62     exit(1);
63     }
64    
65     fd = open(argv[1], O_RDWR, 0);
66     if (fd == -1) {
67     (void)fprintf(stderr, "%s: could not open %s: %s\n",
68     progname, argv[1], strerror(errno));
69     exit(1);
70     }
71    
72     /*
73     * Size does not really matter, it will be rounded-up to a multiple
74     * of the page size automatically.
75     */
76     addr = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
77     MAP_FILE | MAP_SHARED, fd, 0);
78     if (addr == NULL) {
79     (void)fprintf(stderr, "%s: could not mmap %s: %s\n",
80     progname, argv[1], strerror(errno));
81     exit(1);
82     }
83    
84     /*
85     * Check to see if the Mach-O magic bytes are in the header.
86     * If we cared about cross compiling we would also check against
87     * MH_CIGAM and then change the endianness with every access, but
88     * we do not care about that.
89     */
90     machhead = (void *)addr;
91     if (machhead->magic != MH_MAGIC) {
92     (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
93     progname, argv[1]);
94     exit(1);
95     }
96    
97     if (machhead->filetype != MH_EXECUTE) {
98     (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
99     progname, argv[1]);
100     exit(1);
101     }
102    
103     if (machhead->ncmds == 0) {
104     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
105     progname, argv[1]);
106     exit(1);
107     }
108    
109     sc_cmd = (void *)&machhead[1];
110     if (sc_cmd->cmd != LC_SEGMENT){
111     (void)fprintf(stderr, "%s: load segment not first command in %s\n",
112     progname, argv[1]);
113     exit(1);
114     }
115    
116     if (strncmp(sc_cmd->segname, "__PAGEZERO",
117     sizeof (*sc_cmd->segname))) {
118     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
119     progname, argv[1]);
120     exit(1);
121     }
122    
123     /* change the permissions */
124     sc_cmd->maxprot = VM_PROT_ALL;
125     sc_cmd->initprot = VM_PROT_ALL;
126    
127     /*
128     * We do not make __PAGEZERO 8K in this program because then
129     * all of the offsets would be wrong in the object file after
130     * this segment. Instead we use the -pagezero_size option
131     * to link the executable.
132     */
133     if (msync(addr, 0x1000, MS_SYNC) == -1) {
134     (void)fprintf(stderr, "%s: could not sync %s: %s\n",
135     progname, argv[1], strerror(errno));
136     exit(1);
137     }
138    
139     if (munmap(addr, 0x1000) == -1) {
140     (void)fprintf(stderr, "%s: could not unmap %s: %s\n",
141     progname, argv[1], strerror(errno));
142     exit(1);
143     }
144    
145     (void)close(fd);
146    
147     exit(0);
148     }