Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/crunch/crunchide/crunchide.c
106842 views
1
/* $NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $ */
2
/*
3
* Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
4
* Copyright (c) 1994 University of Maryland
5
* All Rights Reserved.
6
*
7
* Permission to use, copy, modify, distribute, and sell this software and its
8
* documentation for any purpose is hereby granted without fee, provided that
9
* the above copyright notice appear in all copies and that both that
10
* copyright notice and this permission notice appear in supporting
11
* documentation, and that the name of U.M. not be used in advertising or
12
* publicity pertaining to distribution of the software without specific,
13
* written prior permission. U.M. makes no representations about the
14
* suitability of this software for any purpose. It is provided "as is"
15
* without express or implied warranty.
16
*
17
* U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23
*
24
* Author: James da Silva, Systems Design and Analysis Group
25
* Computer Science Department
26
* University of Maryland at College Park
27
*/
28
/*
29
* crunchide.c - tiptoes through a symbol table, hiding all defined
30
* global symbols. Allows the user to supply a "keep list" of symbols
31
* that are not to be hidden.
32
*
33
* The point of all this is to allow multiple programs to be linked
34
* together without getting multiple-defined errors.
35
*
36
* For example, consider a program "foo.c". It can be linked with a
37
* small stub routine, called "foostub.c", eg:
38
* int foo_main(int argc, char **argv){ return main(argc, argv); }
39
* like so:
40
* cc -c foo.c foostub.c
41
* ld -r foo.o foostub.o -o foo.combined.o
42
* crunchide -k _foo_main foo.combined.o
43
* at this point, foo.combined.o can be linked with another program
44
* and invoked with "foo_main(argc, argv)". foo's main() and any
45
* other globals are hidden and will not conflict with other symbols.
46
*
47
* TODO:
48
* - resolve the theoretical hanging reloc problem (see check_reloc()
49
* below). I have yet to see this problem actually occur in any real
50
* program. In what cases will gcc/gas generate code that needs a
51
* relative reloc from a global symbol, other than PIC? The
52
* solution is to not hide the symbol from the linker in this case,
53
* but to generate some random name for it so that it doesn't link
54
* with anything but holds the place for the reloc.
55
* - arrange that all the BSS segments start at the same address, so
56
* that the final crunched binary BSS size is the max of all the
57
* component programs' BSS sizes, rather than their sum.
58
*/
59
60
#include <sys/cdefs.h>
61
#ifndef lint
62
__RCSID("$NetBSD: crunchide.c,v 1.8 1997/11/01 06:51:45 lukem Exp $");
63
#endif
64
#include <sys/types.h>
65
#include <sys/stat.h>
66
#include <sys/errno.h>
67
#include <unistd.h>
68
#include <stdio.h>
69
#include <stdlib.h>
70
#include <string.h>
71
#include <fcntl.h>
72
73
#include "extern.h"
74
75
static const char *pname = "crunchide";
76
77
static void usage(void) __dead2;
78
79
static void add_to_keep_list(char *symbol);
80
static void add_file_to_keep_list(char *filename);
81
82
static int hide_syms(const char *filename);
83
84
static int verbose;
85
86
int main(int, char *[]);
87
88
int
89
main(int argc, char **argv)
90
{
91
int ch, errors;
92
93
if(argc > 0) pname = argv[0];
94
95
while ((ch = getopt(argc, argv, "k:f:v")) != -1)
96
switch(ch) {
97
case 'k':
98
add_to_keep_list(optarg);
99
break;
100
case 'f':
101
add_file_to_keep_list(optarg);
102
break;
103
case 'v':
104
verbose = 1;
105
break;
106
default:
107
usage();
108
}
109
110
argc -= optind;
111
argv += optind;
112
113
if(argc == 0) usage();
114
115
errors = 0;
116
while(argc) {
117
if (hide_syms(*argv))
118
errors = 1;
119
argc--, argv++;
120
}
121
122
return errors;
123
}
124
125
static void
126
usage(void)
127
{
128
fprintf(stderr,
129
"usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",
130
pname);
131
exit(1);
132
}
133
134
/* ---------------------------- */
135
136
static struct keep {
137
struct keep *next;
138
char *sym;
139
} *keep_list;
140
141
static void
142
add_to_keep_list(char *symbol)
143
{
144
struct keep *newp, *prevp, *curp;
145
int cmp;
146
147
cmp = 0;
148
149
for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
150
if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
151
152
if(curp && cmp == 0)
153
return; /* already in table */
154
155
newp = (struct keep *) malloc(sizeof(struct keep));
156
if(newp) newp->sym = strdup(symbol);
157
if(newp == NULL || newp->sym == NULL) {
158
fprintf(stderr, "%s: out of memory for keep list\n", pname);
159
exit(1);
160
}
161
162
newp->next = curp;
163
if(prevp) prevp->next = newp;
164
else keep_list = newp;
165
}
166
167
int
168
in_keep_list(const char *symbol)
169
{
170
struct keep *curp;
171
int cmp;
172
173
cmp = 0;
174
175
for(curp = keep_list; curp; curp = curp->next)
176
if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
177
178
return curp && cmp == 0;
179
}
180
181
static void
182
add_file_to_keep_list(char *filename)
183
{
184
FILE *keepf;
185
char symbol[1024];
186
int len;
187
188
if((keepf = fopen(filename, "r")) == NULL) {
189
perror(filename);
190
usage();
191
}
192
193
while(fgets(symbol, sizeof(symbol), keepf)) {
194
len = strlen(symbol);
195
if(len && symbol[len-1] == '\n')
196
symbol[len-1] = '\0';
197
198
add_to_keep_list(symbol);
199
}
200
fclose(keepf);
201
}
202
203
/* ---------------------------- */
204
205
static struct {
206
const char *name;
207
int (*check)(int, const char *); /* 1 if match, zero if not */
208
int (*hide)(int, const char *); /* non-zero if error */
209
} exec_formats[] = {
210
#ifdef NLIST_ELF32
211
{ "ELF32", check_elf32, hide_elf32, },
212
#endif
213
#ifdef NLIST_ELF64
214
{ "ELF64", check_elf64, hide_elf64, },
215
#endif
216
};
217
218
static int
219
hide_syms(const char *filename)
220
{
221
int fd, i, n, rv;
222
223
fd = open(filename, O_RDWR, 0);
224
if (fd == -1) {
225
perror(filename);
226
return 1;
227
}
228
229
rv = 0;
230
231
n = sizeof exec_formats / sizeof exec_formats[0];
232
for (i = 0; i < n; i++) {
233
if (lseek(fd, 0, SEEK_SET) != 0) {
234
perror(filename);
235
goto err;
236
}
237
if ((*exec_formats[i].check)(fd, filename) != 0)
238
break;
239
}
240
if (i == n) {
241
fprintf(stderr, "%s: unknown executable format\n", filename);
242
goto err;
243
}
244
245
if (verbose)
246
fprintf(stderr, "%s is an %s binary\n", filename,
247
exec_formats[i].name);
248
249
if (lseek(fd, 0, SEEK_SET) != 0) {
250
perror(filename);
251
goto err;
252
}
253
rv = (*exec_formats[i].hide)(fd, filename);
254
255
out:
256
close (fd);
257
return (rv);
258
259
err:
260
rv = 1;
261
goto out;
262
}
263
264