I’m trying to figure out ways to dead-strip unneeded RTTI, either in the linker or during LTO. My primary target is ELF AArch64 (Android), but general solutions are appreciated too
A trivial motivating example would be building an executable with the following code:
#include <stdio.h>
#include <stdlib.h>
struct Base { virtual ~Base(); };
struct Derived : Base { virtual ~Derived(); };
Base::~Base() { puts("Goodbye Base"); }
Derived::~Derived() { puts("Goodbye Derived"); }
int main() {
Base *b;
if (rand() > RAND_MAX / 2)
b = new Base();
else
b = new Derived();
delete b;
}
In this case, we aren’t making use of the RTTI for Base
or Derived
, and I’d like it to not be present in the final binary. However, we are making use of their vtables, and the vtables reference the RTTI, so we end up preserving it unnecessarily. I’m looking for some mechanism to be able to eliminate RTTI that’s only referenced by vtables and nowhere else. Some potential mechanisms I could think of:
- The ability to have weak symbol semantics on a relocation instead of a symbol. That is, have a way to mark a relocation such that the relocation by itself doesn’t cause its referenced symbol to be preserved, and if the referenced symbol ends up being dead-stripped, the relocation is just resolved to 0. Vtables would use such relocations for their RTTI references. As far as I know, this doesn’t exist today.
- An LTO pass that goes through all typeinfos and eliminates the ones only used by vtables (accounting for exported symbols in case of shared libraries). This would only work with LTO, of course, but that’s good enough for me.
Do either of those sound reasonable, or are there other good ways for me to accomplish my goal? I’m aware that -fexceptions -fno-rtti
will only emit RTTI where it’s needed for exception handling, but it also emits duplicate RTTI even for types with key functions, which can break exception handling. A hypothetical -fno-rtti-but-still-respect-key-functions
might do exactly what I want, but I don’t know if that’d be acceptable.