summaryrefslogtreecommitdiffstats
path: root/kernel/strip_modules
blob: 0319507f0b0460553f31bf040850bbafa76fee2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#!/bin/sh
#
#	Given a list of objects, strip all static symbols except those
#	required by insmod.
#
#	Copyright Keith Owens <kaos@ocs.com.au>.  GPL.
#	Sat Feb  1 12:52:17 EST 1997
#	
#	Mainly intended for reducing the size of modules to save space
#	on emergency and install disks.  Be aware that removing the
#	static symbols reduces the amount of diagnostic information
#	available for oops.  Not recommended for normal module usage.
#
#	This code requires the modules use MODULE_PARM and EXPORT_.
#	Do not strip modules that have not been converted to use
#	MODULE_PARM or are using the old method of exporting symbols.
#	In particular do not use on modules prior to 2.1.20 (approx).
#
#	The objects are stripped in /tmp, only if the strip works is
#	the original overwritten.  If the command line to strip the
#	symbols becomes too long, the strip is done in multiple passes.
#	Running strip_module twice on the same object is safe (and a
#	waste of time).
#

sizeofptr="/tmp/$$.sizeofptr"
echo 'int main() { return sizeof(void *); }' | gcc -xc - -o $sizeofptr
$sizeofptr
export SIZEOF_POINTER=$?
rm -f $sizeofptr

cat > /tmp/$$.awk <<\EOF
BEGIN	{
	strip = "/usr/bin/objcopy";
	nm = "/usr/bin/nm";
	cp = "/bin/cp";
	mv = "/bin/mv";
	rm = "/bin/rm";
	tmp = "/tmp";
	command_size = 400;	# arbitrary but safe

	getline < "/proc/self/stat";
	pid = $1;
	tmpcopy = tmp "/" pid ".object";
	nmout = tmp "/" pid ".nmout";

	for (i = 1; i < ARGC; ++i)
		strip_module(ARGV[i]);

	do_command(rm " -f " tmpcopy " " nmout);

	exit(0);
}

function strip_module(object,
	keep_symbol, to_strip, symbol, command, changed) {
	do_command(cp " -a " object " " tmpcopy);
	do_command(nm " " tmpcopy " > " nmout);
	# delete array_name sometimes breaks, internal error, play safe
	for (symbol in keep_symbol)
		delete keep_symbol[symbol];
	for (symbol in to_strip)
		delete to_strip[symbol];
	new_module_format = 0;
	ptrskip = 2 + 2 * ENVIRON["SIZEOF_POINTER"];
	while ((getline < nmout) > 0) {
		$0 = substr($0, ptrskip);
		# b static variable, uninitialised
		# d static variable, initialised
		# r static array, initialised
		# t static label/procedures
		print $0 ":" $3 ":" $5 > "/dev/stderr";
		if ($1 ~ /[bdrt]/)
			to_strip[$2] = "";
		else if ($2 ~ /R __ksymtab_/)
			keep_symbol[substr($2, 11)] = "";
		else if ($0 ~ /R __module_parm_/)
			keep_symbol[substr($2, 15)] = "";
		else if ($0 ~ /D __parm_/)
			keep_symbol[substr($2, 8)] = "";
		else if ($3 ~ /__ksymtab/) {
			print "keep " $5 > "/dev/stderr";
			keep_symbol[$5] = "";
		}
		else if ($1 != "?")
			keep_symbol[$2] = "";
		if ($2 ~ /__module/)
			new_module_format = 1;
	}
	close(nmout);
	command = "";
	changed = 0;
	failure = 0;
	if (new_module_format) {
		for (symbol in to_strip) {
			if (!(symbol in keep_symbol)) {
				changed = 1;
				if (length(command) > command_size) {
					failure = failure || do_command(strip command " " tmpcopy);
					command = "";
				}
				command = command " --strip-symbol=" symbol;
			}
		}
	}
	if (command != "") {
		changed = 1;
		failure = failure || do_command(strip command " " tmpcopy);
	}
	if (changed && !failure)
		do_command(mv " " tmpcopy " " object);
}

function do_command(command) {
	if ((ret = system(command)) != 0) {
		giveup("command \"" command "\" failed " ret, ret);
		return 1;
	}
	return 0;
}

function giveup(message, ret) {
	print "strip_module: " message > "/dev/stderr";
#	exit(ret);
}
EOF

awk -f /tmp/$$.awk "$@"
ret=$?
rm -f /tmp/$$.awk
exit $ret