1#!/usr/bin/perl
2#
3#	libfoo.pl
4#	Copyright (C) 2006-2008 Jonathan Zarate
5#
6#	- strip un-needed objects
7#	- create xref of symbols used
8#
9
10$root = $ENV{"TARGETDIR"};
11$uclibc = $ENV{"TOOLCHAIN"};
12$router = $ENV{"SRCBASE"} . "/router";
13
14# toolchain
15$ld = $ENV{"LD"};
16$readelf = $ENV{"READELF"};
17
18sub error
19{
20	print STDERR "\n*** ERROR: " . (shift) . "\n\n";
21	exit 1;
22}
23
24sub basename
25{
26	my $fn = shift;
27	if ($fn =~ /([^\/]+)$/) {
28		return $1;
29	}
30	return $fn;
31}
32
33sub load
34{
35    my $fname = shift;
36
37	if ((-l $fname) ||
38		($fname =~ /\/lib\/modules\/\d+\.\d+\.\d+/) ||
39		($fname =~ /\.(asp|gif|png|svg|js|jsx|css|txt|pat|sh)$/)) {
40		return;
41	}
42
43	if (-d $fname) {
44		my $d;
45		if (opendir($d, $fname)) {
46			foreach (readdir($d)) {
47				if ($_ !~ /^\./) {
48					load($fname . "/" . $_);
49				}
50			}
51			closedir($d);
52		}
53		return;
54	}
55
56
57	my $f;
58	my $base;
59	my $ok;
60	my $s;
61
62	$base = basename($fname);
63	print LOG "\n\nreadelf $base:\n";
64
65	open($f, "${readelf} -WhsdD ${fname} 2>&1 |") || error("readelf - $!\n");
66
67	while (<$f>) {
68		print LOG;
69
70		if (/\s+Type:\s+(\w+)/) {
71			$elf_type{$base} = $1;
72			$ok = 1;
73			last;
74		}
75	}
76
77	if (!$ok) {
78		close($f);
79		return;
80	}
81
82	print "$elf_type{$base} $base", " " x 30, "\r";
83
84	push(@elfs, $base);
85
86	while (<$f>) {
87		print LOG;
88
89		if (/\(NEEDED\)\s+Shared library: \[(.+)\]/) {
90			push(@{$elf_lib{$base}}, $1);
91		}
92		elsif (/\(SONAME\)\s+Library soname: \[(.+)\]/) {
93			if (!($1 eq $base))
94			{
95				$elf_lib_soname{$base} = $1;
96				$elf_lib_soname{$1} = $base;
97			}
98		}
99		elsif (/Symbol table for image:/) {
100			last;
101		}
102	}
103
104	while (<$f>) {
105		print LOG;
106
107		if (/\s+(WEAK|GLOBAL)\s+(?:DEFAULT|VISIBLE)\s+(\w+)\s+(\w+)/) {
108			$s = $3;
109			if ($2 eq 'UND') {
110				if ($1 eq 'GLOBAL') {
111					$elf_ext{$base}{$s} = 1;
112				}
113				else {
114					print LOG "*** not GLOBAL\n";
115				}
116			}
117			elsif ($2 eq 'ABS') {
118			}
119			elsif ($2 =~ /^\d+$/) {
120				$elf_exp{$base}{$s} = 1;
121			}
122			else {
123				print LOG "*** unknown type\n";
124			}
125		}
126		elsif (!/Num Buc:/) {
127			print LOG "*** strange line\n";
128		}
129	}
130
131	close($f);
132}
133
134sub fixDynDep
135{
136	my ($user, $dep) = @_;
137
138	if (!defined $elf_dyn{$user}{$dep}) {
139		push(@{$elf_lib{$user}}, $dep);
140		$elf_dyn{$user}{$dep} = 1;
141
142		print LOG "FixDynDep: $user = $dep\n";
143	}
144}
145
146sub fixDyn
147{
148	my $s;
149
150	foreach (@elfs) {
151		if (/^libipt_.+\.so$/) {
152			fixDynDep("iptables", $_);
153			fixDynDep($_, "libxtables.so");
154			fixDynDep($_, "xtables-multi");
155		}
156		elsif (/^libip6t_.+\.so$/) {
157			fixDynDep("iptables", $_);
158			fixDynDep($_, "libxtables.so");
159		}
160		elsif (/^libxt_.+\.so$/) {
161			fixDynDep($_, "libxtables.so");
162		}
163		elsif (/^CP\d+\.so$/) {
164			fixDynDep("smbd", $_);
165		}
166	}
167
168	fixDynDep("l2tpd", "cmd.so");
169	fixDynDep("l2tpd", "sync-pppd.so");
170	fixDynDep("pppd", "pppol2tp.so");
171	fixDynDep("pppd", "pptp.so");
172	fixDynDep("pppd", "rp-pppoe.so");
173	fixDynDep("libcrypto.so.1.0.0", "libssl.so.1.0.0");
174
175	fixDynDep("xtables-multi", "libip4tc.so");
176	fixDynDep("xtables-multi", "libip6tc.so");
177	fixDynDep("xtables-multi", "libxtables.so");
178
179	fixDynDep("libxt_RATEEST.so", "libm.so.0");
180	fixDynDep("libxt_statistic.so", "libm.so.0");
181
182## charles add
183#	    fixDynDep("libsmbclient.so.0", "libpthread.so.0");
184	fixDynDep("mod_smbdav.so", "libshared.so");
185	fixDynDep("mod_smbdav.so", "libnvram.so");
186	fixDynDep("mod_smbdav.so", "libsqlite3.so.0");
187    fixDynDep("mod_smbdav.so", "libxml2.so.2");
188	fixDynDep("mod_smbdav.so", "libsmbclient.so.0");
189	fixDynDep("mod_smbdav.so", "libpthread.so.0");
190	   fixDynDep("lighttpd", "libpthread.so.0");
191	   fixDynDep("lighttpd-arpping", "libpthread.so.0");
192	   fixDynDep("lighttpd-arpping", "libsmbclient.so.0");
193
194	fixDynDep("lighttpd", "libcrypto.so.1.0.0");
195	fixDynDep("lighttpd", "libssl.so.1.0.0");
196        fixDynDep("lighttpd", "libpcre.so.0.0.1");
197        fixDynDep("lighttpd", "mod_accesslog.so");
198        fixDynDep("lighttpd", "mod_alias.so");
199        fixDynDep("lighttpd", "mod_auth.so");
200        fixDynDep("lighttpd", "mod_cml.so");
201        fixDynDep("lighttpd", "mod_cgi.so");
202        fixDynDep("lighttpd", "mod_compress.so");
203        fixDynDep("lighttpd", "mod_dirlisting.so");
204        fixDynDep("lighttpd", "mod_proxy.so");
205        fixDynDep("lighttpd", "mod_redirect.so");
206        fixDynDep("lighttpd", "mod_rewrite.so");
207        fixDynDep("lighttpd", "mod_ssi.so");
208        fixDynDep("lighttpd", "mod_staticfile.so");
209        fixDynDep("lighttpd", "mod_status.so");
210        fixDynDep("lighttpd", "mod_trigger_b4_dl.so");
211        fixDynDep("lighttpd", "mod_userdir.so");
212        fixDynDep("lighttpd", "mod_webdav.so");
213        fixDynDep("lighttpd", "mod_usertrack.so");
214        fixDynDep("lighttpd", "mod_ssi.so");
215        fixDynDep("lighttpd", "mod_scgi.so");
216        fixDynDep("lighttpd", "mod_access.so");
217        fixDynDep("lighttpd", "mod_evasive.so");
218        fixDynDep("lighttpd", "mod_evhost.so");
219        fixDynDep("lighttpd", "mod_expire.so");
220        fixDynDep("lighttpd", "mod_extforward.so");
221        fixDynDep("lighttpd", "mod_fastcgi.so");
222        fixDynDep("lighttpd", "mod_flv_streaming.so");
223        fixDynDep("lighttpd", "mod_indexfile.so");
224        fixDynDep("lighttpd", "mod_magnet.so");
225        fixDynDep("lighttpd", "mod_mysql_vhost.so");
226        fixDynDep("lighttpd", "mod_rrdtool.so");
227        fixDynDep("lighttpd", "mod_secdownload.so");
228        fixDynDep("lighttpd", "mod_setenv.so");
229        fixDynDep("lighttpd", "mod_simple_vhost.so");
230        fixDynDep("mod_webdav.so", "libsqlite3.so.0");
231        fixDynDep("mod_webdav.so", "libxml2.so.2");
232## charles add
233		fixDynDep("lighttpd", "mod_smbdav.so");
234        fixDynDep("lighttpd", "libshared.so");
235        fixDynDep("lighttpd", "libnvram.so");
236		fixDynDep("lighttpd", "libxml2.so.2");
237		fixDynDep("libbcm.so", "libshared.so");
238		fixDynDep("libbcm.so", "libc.so.0");
239#   fixDynDep("lighttpd", "libdisk.so");
240        fixDynDep("lighttpd", "mod_smbdav_access.so");
241        fixDynDep("mod_smbdav_access.so", "libdisk.so");
242
243#!!TB - Updated Broadcom WL driver
244	fixDynDep("libbcmcrypto.so", "libc.so.0");
245	fixDynDep("nas", "libbcmcrypto.so");
246	fixDynDep("wl", "libbcmcrypto.so");
247	fixDynDep("nas", "libc.so.0");
248	fixDynDep("wl", "libc.so.0");
249
250	fixDynDep("libneon.so.27.2.6", "libz.so.1");
251	fixDynDep("libneon.so.27.2.6", "libcrypto.so.1.0.0");
252	fixDynDep("mod_create_captcha_image.so", "mod_webdav.so");
253}
254
255sub usersOf
256{
257	my $name = shift;
258	my $sym = shift;
259	my @x;
260	my $e;
261	my $l;
262
263	@x = ();
264	foreach $e (@elfs) {
265		foreach $l (@{$elf_lib{$e}}) {
266			if ($l eq $name || (defined($elf_lib_soname{$l}) && $elf_lib_soname{$l} eq $name)) {
267				if ((!defined $sym) || (defined $elf_ext{$e}{$sym})) {
268					push(@x, $e);
269				}
270				last;
271			}
272		}
273	}
274	return @x;
275}
276
277sub resolve
278{
279	my $name = shift;
280	my $sym = shift;
281	my $l;
282
283	foreach $l (@{$elf_lib{$name}}) {
284#		print "\n$l $sym ", $elf_exp{$l}{$sym}, "\n";
285		return $l if (defined $elf_exp{$l}{$sym});
286	}
287	return "*** unresolved ***";
288}
289
290sub fillGaps
291{
292	my $name;
293	my $sym;
294	my @users;
295	my $u;
296	my $t;
297	my $found;
298
299#	print "Resolving implicit links...\n";
300
301	foreach $name (@elfs) {
302		foreach $sym (keys %{$elf_ext{$name}}) {
303			$found = 0;
304
305			if ($sym eq '__uClibc_start_main') {
306				$sym = '__uClibc_main';
307			}
308
309			#  __gnu_local_gp is defined specially by the linker on MIPS
310			if ($sym eq '__gnu_local_gp') {
311				$found = 1;
312			}
313			elsif (resolve($name, $sym) eq "*** unresolved ***") {
314				@users = usersOf($name);
315				foreach $u (@users) {
316					# if exported by $u
317					if (defined $elf_exp{$u}{$sym}) {
318						fixDynDep($name, $u);
319						$found = 1;
320					}
321					# if exported by shared libs of $u
322					if (($t = resolve($u, $sym)) ne "*** unresolved ***") {
323						fixDynDep($name, $t);
324						$found = 1;
325					}
326				}
327
328				if ($found == 0) {
329#					if (!$name eq 'u2ec') {
330					if (!$name eq 'mt-daapd-svn-1696') {
331						print "Unable to resolve $sym used by $name\n", @users;
332						exit 1;
333					}
334				}
335			}
336		}
337	}
338}
339
340sub tab
341{
342	my $current = shift;
343	my $target = shift;
344	my $s = "";
345	my $n;
346
347	while (1) {
348		$n = $current + (4 - ($current % 4));
349		last if ($n > $target);
350		$s = $s . "\t";
351		$current = $n;
352	}
353	while ($current < $target) {
354		$s = $s . " ";
355		$current++;
356	}
357	return $s;
358}
359
360sub genXref
361{
362	my $f;
363	my $fname;
364	my $s;
365	my @u;
366
367#	print "Generating Xref Report...\n";
368
369	open($f, ">libfoo_xref.txt");
370	foreach $fname (sort keys %elf_type) {
371		print $f "$fname:\n";
372
373		if (scalar(@{$elf_lib{$fname}}) > 0) {
374			print $f "Dependency:\n";
375			foreach $s (sort @{$elf_lib{$fname}}) {
376				print $f "\t$s", defined $elf_dyn{$fname}{$s} ? " (dyn)\n" : "\n";
377			}
378		}
379
380		if (scalar(keys %{$elf_exp{$fname}}) > 0) {
381			print $f "Export:\n";
382			foreach $s (sort keys %{$elf_exp{$fname}}) {
383				@u = usersOf($fname, $s);
384				if (scalar(@u) > 0) {
385					print $f "\t$s", tab(length($s) + 4, 40), " > ", join(",", @u), "\n";
386				}
387				else {
388					print $f "\t$s\n";
389				}
390			}
391		}
392
393		if (scalar(keys %{$elf_ext{$fname}}) > 0) {
394			print $f "External:\n";
395			foreach $s (sort keys %{$elf_ext{$fname}}) {
396				print $f "\t$s", tab(length($s) + 4, 40), " < ", resolve($fname, $s), "\n";
397			}
398		}
399
400		print $f "\n";
401	}
402	close($f);
403}
404
405sub verifyUnresolved
406{
407	my $name;
408	my $sym;
409	my $lib;
410	my $found;
411	my @unresolved;
412
413	foreach $name (@elfs) {
414		foreach $sym (keys %{$elf_ext{$name}}) {
415			$found = 0;
416			foreach $lib (@{$elf_lib{$name}}) {
417				if (defined($elf_exp{$lib}{$sym}) || (defined($elf_lib_soname{$lib}) && defined($elf_exp{$elf_lib_soname{$lib}}{$sym}))) {
418					$found = 1;
419					last;
420				}
421			}
422			if($found == 0) {
423				print "WARNING: unresolved $name---$sym\n";
424				push(@unresolved, "$name---$sym");
425			}
426		}
427	}
428	return @unresolved;
429}
430
431sub genSO
432{
433	my ($so, $arc, $strip, $opt) = @_;
434	my $name = basename($so);
435	my $sym;
436	my $fn;
437	my $inuse;
438	my @used;
439	my @unused;
440	my $cmd;
441	my $before, $after;
442
443	if (!-f $so) {
444		print "$name: not found, skipping...\n";
445		return 0;
446	}
447
448	#!!TB
449	if (!-f $arc) {
450		print "$arc: not found, skipping...\n";
451		return 0;
452	}
453
454	foreach $sym (sort keys %{$elf_exp{$name}}) {
455		if ((scalar(usersOf($name, $sym)) > 0) || (${strip} eq "no")) {
456			push(@used, $sym);
457		}
458		else {
459			push(@unused, $sym);
460		}
461	}
462
463#	print "\n$name: Attempting to link ", scalar(@used), " and remove ", scalar(@unused), " objects...\n";
464
465	print LOG "\n\n${base}\n";
466
467	$cmd = "${ld} -shared -s -z combreloc --warn-common --fatal-warnings ${opt} -soname ${name} -o ${so}";
468	foreach (@{$elf_lib{$name}}) {
469		if ((!$elf_dyn{$name}{$_}) && (/^lib(.+)\.so/)) {
470			$cmd .= " -l$1";
471		}
472		else {
473#			print LOG "Not marking for linkage: $_\n";
474		}
475	}
476#	print "$cmd -u... ${arc}\n";
477	my @u = usersOf($name);
478	if ((scalar(@used) == 0) && (scalar(@u) > 0)) {
479		print "$name: WARNING: Library symbol is not used by anything, but linked by (@u). so keep it ...\n";
480	}
481	elsif (scalar(@used) == 0) {
482		print "$name: WARNING: Library is not used by anything, deleting...\n";
483		unlink $so;
484#		<>;
485		return 0;
486	}
487	$cmd .= " -u " . join(" -u ", @used) . " ". $arc;
488
489	print LOG "Command: $cmd\n";
490	print LOG "Used: ", join(",", @used), "\n";
491	print LOG "Unused: ", join(",", @unused), "\n";
492
493	$before = -s $so;
494
495	system($cmd);
496	if ($? != 0) {
497		error("ld returned $?");
498	}
499
500	$after = -s $so;
501
502	print "$name: Attempted to remove ", scalar(@unused), "/", scalar(@unused) + scalar(@used), " symbols. ";
503	printf "%.2fK - %.2fK = %.2fK\n", $before / 1024, $after / 1024, ($before - $after) / 1024;
504
505#	print "\n$name: Attempting to link ", scalar(@used), " and remove ", scalar(@unused), " objects...\n";
506#	printf "Before: %.2fK / After: %.2fK / Removed: %.2fK\n\n", $before / 1024, $after / 1024, ($before - $after) / 1024;
507
508	return ($before > $after)
509}
510
511
512##
513##
514##
515
516#	print "\nlibfoo.pl - fooify shared libraries\n";
517#	print "Copyright (C) 2006-2007 Jonathan Zarate\n\n";
518
519if ((!-d $root) || (!-d $uclibc) || (!-d $router)) {
520	print "Missing or invalid environment variables\n";
521	exit(1);
522}
523
524#open(LOG, ">libfoo.debug");
525open(LOG, ">/dev/null");
526
527print "Loading...\r";
528load($root);
529print "Finished loading files.", " " x 30, "\r";
530
531fixDyn();
532fillGaps();
533
534genXref();
535
536$stripshared = "yes";
537if ($ARGV[0] eq "--noopt") {
538	$stripshared = "no";
539}
540
541# WAR for a weird "ld" bug: unless we drag in these few functions, re-linking
542# libpthread.so.0 completely screws it up - at least in the current toolchain
543# (binutils 2.20.1 / gcc 4.2.4) :(
544$libpthreadwar = "-u pthread_mutexattr_init -u pthread_mutexattr_settype -u pthread_mutexattr_destroy";
545
546verifyUnresolved();
547
548genSO("${root}/lib/libc.so.0", "${uclibc}/lib/libc.a", "${stripshared}", "-init __uClibc_init ${uclibc}/lib/optinfo/interp.os");
549genSO("${root}/lib/libresolv.so.0", "${uclibc}/lib/libresolv.a", "${stripshared}");
550genSO("${root}/lib/libcrypt.so.0", "${uclibc}/lib/libcrypt.a", "${stripshared}");
551genSO("${root}/lib/libm.so.0", "${uclibc}/lib/libm.a", "${stripshared}");
552genSO("${root}/lib/libpthread.so.0", "${uclibc}/lib/libpthread.a", "${stripshared}", "${libpthreadwar}");
553genSO("${root}/lib/libutil.so.0", "${uclibc}/lib/libutil.a", "${stripshared}");
554#  genSO("${root}/lib/libdl.so.0", "${uclibc}/lib/libdl.a", "${stripshared}");
555#  genSO("${root}/lib/libnsl.so.0", "${uclibc}/lib/libnsl.a", "${stripshared}");
556
557genSO("${root}/usr/lib/libcrypto.so.1.0.0", "${router}/openssl/libcrypto.a");
558genSO("${root}/usr/lib/libssl.so.1.0.0", "${router}/openssl/libssl.a", "", "-L${router}/openssl");
559
560genSO("${root}/usr/lib/libzebra.so", "${router}/zebra/lib/libzebra.a");
561genSO("${root}/usr/lib/libz.so.1", "${router}/zlib/libz.a");
562genSO("${root}/usr/lib/libjpeg.so", "${router}/jpeg/libjpeg.a");
563genSO("${root}/usr/lib/libsqlite3.so.0", "${router}/sqlite/.libs/libsqlite3.a");
564genSO("${root}/usr/lib/libogg.so.0", "${router}/libogg/src/.libs/libogg.a");
565genSO("${root}/usr/lib/libvorbis.so.0", "${router}/libvorbis/lib/.libs/libvorbis.a", "", "-L${router}/libogg/src/.libs");
566genSO("${root}/usr/lib/libid3tag.so.0", "${router}/libid3tag/.libs/libid3tag.a", "", "-L${router}/zlib");
567genSO("${root}/usr/lib/libexif.so.12", "${router}/libexif/libexif/.libs/libexif.a");
568genSO("${root}/usr/lib/libFLAC.so.8", "${router}/flac/src/libFLAC/.libs/libFLAC.a", "", "-L${router}/libogg/src/.libs");
569genSO("${root}/usr/lib/libavcodec.so.52", "${router}/ffmpeg/libavcodec/libavcodec.a", "", "-L${router}/ffmpeg/libavutil -L${router}/zlib");
570genSO("${root}/usr/lib/libavutil.so.50", "${router}/ffmpeg/libavutil/libavutil.a");
571genSO("${root}/usr/lib/libavformat.so.52", "${router}/ffmpeg/libavformat/libavformat.a", "", "-L${router}/ffmpeg/libavutil -L${router}/ffmpeg/libavcodec -L${router}/zlib");
572genSO("${root}/usr/lib/libsmb.so", "${router}/samba/source/bin/libsmb.a");
573genSO("${root}/usr/lib/libbigballofmud.so", "${router}/samba3/source/bin/libbigballofmud.a");
574
575genSO("${root}/usr/lib/liblzo2.so.2", "${router}/lzo/src/.libs/liblzo2.a");
576#	genSO("${root}/usr/lib/libtamba.so", "${router}/samba3/source/bin/libtamba.a");
577#	genSO("${root}/usr/lib/libiptc.so", "${router}/iptables/libiptc/libiptc.a");
578#	genSO("${root}/usr/lib/libshared.so", "${router}/shared/libshared.a");
579#	genSO("${root}/usr/lib/libnvram.so", "${router}/nvram/libnvram.a");
580#	genSO("${root}/usr/lib/libusb-1.0.so.0", "${router}/libusb10/libusb/.libs/libusb-1.0.a");
581#	genSO("${root}/usr/lib/libusb-0.1.so.4", "${router}/libusb/libusb/.libs/libusb.a", "", "-L${router}/libusb10/libusb/.libs");
582genSO("${root}/usr/lib/libbcmcrypto.so", "${router}/libbcmcrypto/libbcmcrypto.a");
583
584
585print "\n";
586
587close(LOG);
588exit(0);
589