1 | /*␊ |
2 | * Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.␊ |
3 | *␊ |
4 | * ␊ |
5 | * Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights␊ |
6 | * Reserved. This file contains Original Code and/or Modifications of␊ |
7 | * Original Code as defined in and that are subject to the Apple Public␊ |
8 | * Source License Version 2.0 (the "License"). You may not use this file␊ |
9 | * except in compliance with the License. Please obtain a copy of the␊ |
10 | * License at http://www.apple.com/publicsource and read it before using␊ |
11 | * this file.␊ |
12 | * ␊ |
13 | * The Original Code and all software distributed under the License are␊ |
14 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER␊ |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,␊ |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,␊ |
17 | * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the␊ |
18 | * License for the specific language governing rights and limitations␊ |
19 | * under the License.␊ |
20 | * ␊ |
21 | */␊ |
22 | #include <stdio.h>␊ |
23 | #include <stdlib.h>␊ |
24 | #include <stdbool.h>␊ |
25 | #include <mach/mach.h>␊ |
26 | #include <mach/mach_error.h>␊ |
27 | #include <sys/file.h>␊ |
28 | #include <mach-o/loader.h>␊ |
29 | #include <libkern/OSByteOrder.h>␊ |
30 | #include <unistd.h>␊ |
31 | ␊ |
32 | int␉infile, outfile;␊ |
33 | ␊ |
34 | struct mach_header␉mh;␊ |
35 | void *␉␉cmds;␊ |
36 | ␊ |
37 | static bool␉swap_ends;␊ |
38 | ␊ |
39 | static unsigned long swap(unsigned long x)␊ |
40 | {␊ |
41 | if (swap_ends)␉return OSSwapInt32(x);␊ |
42 | else␉␉␉return x;␊ |
43 | }␊ |
44 | ␊ |
45 | int␊ |
46 | main(int argc, char *argv[])␊ |
47 | {␊ |
48 | kern_return_t␉result;␊ |
49 | vm_address_t␉data;␊ |
50 | int␉␉␉nc, ncmds;␊ |
51 | char *␉␉cp;␊ |
52 | ␊ |
53 | if (argc == 2)␊ |
54 | ␉{␊ |
55 | ␉␉infile = open(argv[1], O_RDONLY);␊ |
56 | ␉␉if (infile < 0)␉␉goto usage;␊ |
57 | ␉␉outfile = fileno(stdout);␊ |
58 | }␊ |
59 | else if (argc == 3)␊ |
60 | ␉{␊ |
61 | ␉infile = open(argv[1], O_RDONLY);␊ |
62 | ␉␉if (infile < 0)␉␉goto usage;␊ |
63 | ␉␉outfile = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0644);␊ |
64 | ␉␉if (outfile < 0)␉goto usage;␊ |
65 | }␊ |
66 | else ␊ |
67 | ␉{␊ |
68 | ␉usage:␊ |
69 | ␉fprintf(stderr, "usage: machOconv inputfile [outputfile]\n");␊ |
70 | ␉␉exit(1);␊ |
71 | }␊ |
72 | ␊ |
73 | nc = read(infile, &mh, sizeof (mh));␊ |
74 | if (nc < 0)␊ |
75 | ␉{␊ |
76 | ␉␉perror("read mach header");␊ |
77 | ␉␉exit(1);␊ |
78 | }␊ |
79 | ␊ |
80 | if (nc < (int)sizeof (mh))␊ |
81 | ␉{␊ |
82 | ␉␉fprintf(stderr, "read mach header: premature EOF %d\n", nc);␊ |
83 | ␉␉exit(1);␊ |
84 | }␊ |
85 | ␊ |
86 | ␊ |
87 | if (mh.magic == MH_MAGIC)␉␉swap_ends = false;␊ |
88 | else if (mh.magic == MH_CIGAM)␉swap_ends = true;␊ |
89 | else␊ |
90 | ␉{␊ |
91 | ␉fprintf(stderr, "bad magic number %lx\n", (unsigned long)mh.magic);␊ |
92 | ␉␉exit(1);␊ |
93 | }␊ |
94 | ␊ |
95 | cmds = calloc(swap(mh.sizeofcmds), sizeof (char));␊ |
96 | if (cmds == 0)␊ |
97 | ␉{␊ |
98 | ␉␉fprintf(stderr, "alloc load commands: no memory\n");␊ |
99 | ␉␉exit(1);␊ |
100 | }␊ |
101 | nc = read(infile, cmds, swap(mh.sizeofcmds));␊ |
102 | if (nc < 0)␊ |
103 | ␉{␊ |
104 | ␉␉perror("read load commands");␊ |
105 | ␉␉exit(1);␊ |
106 | }␊ |
107 | if (nc < (int)swap(mh.sizeofcmds))␊ |
108 | ␉{␊ |
109 | ␉␉fprintf(stderr, "read load commands: premature EOF %d\n", nc);␊ |
110 | ␉␉exit(1);␊ |
111 | }␊ |
112 | ␊ |
113 | ␉unsigned long vmstart = (unsigned long)-1;␊ |
114 | ␊ |
115 | ␉// First pass: determine actual load address␊ |
116 | ␉for (ncmds = swap(mh.ncmds), cp = cmds;␊ |
117 | ␉␉ ncmds > 0; ncmds--)␊ |
118 | ␉{␊ |
119 | #define lcp␉((struct load_command *)cp)␊ |
120 | #define scp␉((struct segment_command *)cp)␊ |
121 | ␊ |
122 | ␉␉switch(swap(lcp->cmd))␊ |
123 | ␉␉{␊ |
124 | ␉␉␉case LC_SEGMENT:␊ |
125 | ␉␉␉␉if(vmstart > swap(scp->vmaddr)) ␊ |
126 | ␉␉␉␉{␊ |
127 | ␉␉␉␉␉vmstart = swap(scp->vmaddr);␊ |
128 | ␉␉␉␉}␊ |
129 | ␉␉}␊ |
130 | ␉␉cp += swap(lcp->cmdsize);␊ |
131 | ␊ |
132 | ␉}␊ |
133 | ␊ |
134 | ␉// Second pass: output to file.␊ |
135 | ␉for (ncmds = swap(mh.ncmds), cp = cmds;␊ |
136 | ␉␉ ncmds > 0; ncmds--)␊ |
137 | ␉{␊ |
138 | #define lcp␉((struct load_command *)cp)␊ |
139 | #define scp␉((struct segment_command *)cp)␊ |
140 | ␊ |
141 | ␉ bool␉isDATA;␊ |
142 | ␉ unsigned␉vmsize;␊ |
143 | ␊ |
144 | ␉␉switch(swap(lcp->cmd))␊ |
145 | ␉␉{␊ |
146 | ␉␉␉case LC_SEGMENT:␊ |
147 | ␉␉␉␉isDATA = (strcmp(scp->segname, "__DATA") == 0);␊ |
148 | ␉␉␉␉if (isDATA)␊ |
149 | ␉␉␉␉{␊ |
150 | ␉␉␉␉␉vmsize = swap(scp->filesize);␊ |
151 | ␉␉␉␉}␊ |
152 | ␉␉␉␉else␊ |
153 | ␉␉␉␉{␊ |
154 | ␉␉␉␉␉vmsize = swap(scp->vmsize);␊ |
155 | ␉␉␉␉}␊ |
156 | ␊ |
157 | ␉␉␉␉result = vm_allocate(mach_task_self(), &data, vmsize, true);␊ |
158 | ␉␉␉␉if (result != KERN_SUCCESS)␊ |
159 | ␉␉␉␉{␊ |
160 | ␉␉␉␉␉mach_error("vm_allocate segment data", result);␊ |
161 | ␉␉␉␉␉exit(1);␊ |
162 | ␉␉␉␉}␊ |
163 | ␊ |
164 | ␉␉␉␉lseek(infile, swap(scp->fileoff), L_SET);␊ |
165 | ␉␉␉␉nc = read(infile, (void *)data, swap(scp->filesize));␊ |
166 | ␉␉␉␉if (nc < 0) {␊ |
167 | ␉␉␉␉␉perror("read segment data");␊ |
168 | ␉␉␉␉␉exit(1);␊ |
169 | ␉␉␉␉}␊ |
170 | ␉␉␉␉if (nc < (int)swap(scp->filesize))␊ |
171 | ␉␉␉␉{␊ |
172 | ␉␉␉␉␉fprintf(stderr, "read segment data: premature EOF %d\n", nc);␊ |
173 | ␉␉␉␉␉exit(1);␊ |
174 | ␉␉␉␉}␊ |
175 | ␊ |
176 | ␉␉␉␉lseek(outfile, swap(scp->vmaddr) - vmstart, L_SET);␊ |
177 | ␉␉␉␉nc = write(outfile, (void *)data, vmsize);␊ |
178 | ␉␉␉␉if (nc < (int)vmsize)␊ |
179 | ␉␉␉␉{␊ |
180 | ␉␉␉␉␉perror("write segment data");␊ |
181 | ␉␉␉␉␉exit(1);␊ |
182 | ␉␉␉␉}␊ |
183 | ␊ |
184 | ␉␉␉␉vm_deallocate(mach_task_self(), data, vmsize);␊ |
185 | ␉␉␉␉break;␊ |
186 | ␉␉}␊ |
187 | ␊ |
188 | ␉␉cp += swap(lcp->cmdsize);␊ |
189 | ␉}␊ |
190 | ␉␊ |
191 | ␉exit(0);␊ |
192 | }␊ |
193 | |