ANNOUNCE: uselex.rb - useless exports extinguisher
Ladies and gentlemen! Welcome new (tiny) tool to find another kind of C/C++ code deficiency: needlessly externally visible symbols.
TL;DR:
uselex.rb /path/to/project/build/dir/ find -name '*.o'
Lives here.
Let’s consider simple example:
// main.c
#include <stdio.h>
int add_a_to_b (int a, int b)
{
return a + b;
}
int main (int argc, char * argv[])
{
return add_a_to_b (argc, 4);
}
and build it:
-O2 -c main.c
$ gcc -d a.o
$ objdump >:
0000000000000000 <add_a_to_blea (%rdi,%rsi,1),%eax
0: 8d 04 37
3: c3 retq.text.startup:
Disassembly of section >:
0000000000000000 <mainlea 0x4(%rdi),%eax
0: 8d 47 04 3: c3 retq
See that useleless piece of generated code? It’s add_a_to_b. To make sure we don’t need it we should add static keyword to it. (provided nobody from another module uses that function as well obviously).
This
// main.c
#include <stdio.h>
static int add_a_to_b (int a, int b)
{
return a + b;
}
int main (int argc, char * argv[])
{
return add_a_to_b (argc, 4);
}
will give
>:
0000000000000000 <mainlea 0x4(%rdi),%eax
0: 8d 47 04 3: c3 retq
As you see a chunk of .text section gone away. In many cases it helps in more aggressive inlining. Large programs have a ton of useleccly exported stuff: global variables, global functions, global constans. They are usually used only in one place (even if they were used in many places long ago).
I’ve decided to try to write small tool to find such unused exports uselex.rb:
$ uselex.rb main.o
add_a_to_b: [R]: exported from: a.o
Caught the guy. Let’s try for more advanced projects:
~/dev/git/btrfs-progs $ uselex.rb `find -name '*.o'`
write_all_supers: [R]: exported from: ./disk-io.o
btrfs_lookup_dir_index_item: [R]: exported from: ./dir-item.o
update_seeding_flag: [R]: exported from: ./btrfstune.o
enable_extrefs_flag: [R]: exported from: ./btrfstune.o
write_tree_block: [R]: exported from: ./disk-io.o
receive_cmd_group: [R]: exported from: ./cmds-receive.o
radix_tree_delete: [R]: exported from: ./radix-tree.o
...
Not all of them are problems. btrfs-progs exports a library, thus you need to ignore functions exported from installable headers.
And the linux kernel for stress test:
~/linux-2.6-mytree $ time uselex.rb `find -name '*.o'` | wc -l
3808
real 0m15.971s
user 0m7.526s
sys 0m7.070s
You can read some implementation details in help output for uselex.
Thanks for your patience!