ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/Darwin/lowmem.c
Revision: 1.5
Committed: 2007-06-15T22:54:24Z (17 years, 3 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.4: +16 -5 lines
Log Message:
Fix REAL_ADDRESSING mode on MacOS X, aka move Mach defines to config_macosx.h
and fix lowmem (BLESS) to handle other-endian 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    
33     static const char progname[] = "lowmem";
34    
35 gbeauche 1.5 static int do_swap = 0;
36    
37     static uint32_t target_uint32(uint32_t value)
38     {
39     if (do_swap)
40     value = NXSwapInt(value);
41     return value;
42     }
43    
44 gbeauche 1.1 /*
45     * Under Mach there is very little assumed about the memory map of object
46     * files. It is the job of the loader to create the initial memory map of an
47     * executable. In a Mach-O executable there will be numerous loader commands
48     * that the loader must process. Some of these will create the initial memory
49     * map used by the executable. Under Darwin the static object file linker,
50     * ld, automatically adds the __PAGEZERO segment to all executables. The
51     * default size of this segment is the page size of the target system and
52     * the initial and maximum permissions are set to allow no access. This is so
53     * that all programs fault on a NULL pointer dereference. Arguably this is
54     * incorrect and the maximum permissions shoould be rwx so that programs can
55     * change this default behavior. Then programs could be written that assume
56     * a null string at the null address, which was the convention on some
57     * systems. In our case we need to have 8K mapped at zero for the low memory
58     * globals and this program modifies the segment load command in the
59     * basiliskII executable so that it can be used for data.
60     */
61    
62     int
63     main(int argc, const char *argv[])
64     {
65     int fd;
66     char *addr;
67     struct mach_header *machhead;
68     struct segment_command *sc_cmd;
69    
70     if (argc != 2) {
71     (void)fprintf(stderr, "Usage: %s executable\n", progname);
72     exit(1);
73     }
74    
75     fd = open(argv[1], O_RDWR, 0);
76     if (fd == -1) {
77     (void)fprintf(stderr, "%s: could not open %s: %s\n",
78     progname, argv[1], strerror(errno));
79     exit(1);
80     }
81    
82     /*
83     * Size does not really matter, it will be rounded-up to a multiple
84     * of the page size automatically.
85     */
86     addr = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
87     MAP_FILE | MAP_SHARED, fd, 0);
88     if (addr == NULL) {
89     (void)fprintf(stderr, "%s: could not mmap %s: %s\n",
90     progname, argv[1], strerror(errno));
91     exit(1);
92     }
93    
94     /*
95     * Check to see if the Mach-O magic bytes are in the header.
96     * If we cared about cross compiling we would also check against
97     * MH_CIGAM and then change the endianness with every access, but
98     * we do not care about that.
99     */
100     machhead = (void *)addr;
101 gbeauche 1.5 if (machhead->magic == MH_CIGAM)
102     do_swap = 1;
103     if (target_uint32(machhead->magic) != MH_MAGIC) {
104 gbeauche 1.1 (void)fprintf(stderr, "%s: %s does not appear to be a Mach-O object file\n",
105     progname, argv[1]);
106     exit(1);
107     }
108    
109 gbeauche 1.5 if (target_uint32(machhead->filetype) != MH_EXECUTE) {
110 gbeauche 1.1 (void)fprintf(stderr, "%s: %s does not appear to be an executable file\n",
111     progname, argv[1]);
112     exit(1);
113     }
114    
115     if (machhead->ncmds == 0) {
116     (void)fprintf(stderr, "%s: %s does not contain any load commands\n",
117     progname, argv[1]);
118     exit(1);
119     }
120    
121     sc_cmd = (void *)&machhead[1];
122 gbeauche 1.5 if (target_uint32(sc_cmd->cmd) != LC_SEGMENT){
123 gbeauche 1.1 (void)fprintf(stderr, "%s: load segment not first command in %s\n",
124     progname, argv[1]);
125     exit(1);
126     }
127    
128     if (strncmp(sc_cmd->segname, "__PAGEZERO",
129     sizeof (*sc_cmd->segname))) {
130     (void)fprintf(stderr, "%s: zero page not first segment in %s\n",
131     progname, argv[1]);
132     exit(1);
133     }
134    
135     /* change the permissions */
136 gbeauche 1.5 sc_cmd->maxprot = target_uint32(VM_PROT_ALL);
137     sc_cmd->initprot = target_uint32(VM_PROT_ALL);
138 gbeauche 1.1
139     /*
140     * We do not make __PAGEZERO 8K in this program because then
141     * all of the offsets would be wrong in the object file after
142     * this segment. Instead we use the -pagezero_size option
143     * to link the executable.
144     */
145     if (msync(addr, 0x1000, MS_SYNC) == -1) {
146     (void)fprintf(stderr, "%s: could not sync %s: %s\n",
147     progname, argv[1], strerror(errno));
148     exit(1);
149     }
150    
151     if (munmap(addr, 0x1000) == -1) {
152     (void)fprintf(stderr, "%s: could not unmap %s: %s\n",
153     progname, argv[1], strerror(errno));
154     exit(1);
155     }
156    
157     (void)close(fd);
158    
159     exit(0);
160     }