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