ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.3
Committed: 2005-01-30T21:42:14Z (19 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-17
Changes since 1.2: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * lowmem.c - enable access to low memory globals on Darwin
3 *
4 * Copyright (c) 2003 Michael Z. Sliczniak
5 *
6 * Basilisk II (C) 1997-2005 Christian Bauer
7 *
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 }