Abstract
The Go linker tries to remove functions that are never called in a step called "deadcode elimination". During this step the linker visits the symbol graph, starting from the entry point of the program, and marks every reachable symbol, i.e. everything that is called either directly or indirectly, through a function pointer or through an interface. All unreachable symbols are then removed and will not be included in the final executable.
However if during this process if the linker sees that one of the following methods are reachable:
- reflect.Value.Method
- reflect.Value.MethodByName
- reflect.Type.Method
- reflect.Type.MethodByName
then a more relaxed version of deadcode elimination is run and every exported method of any reachable type is considered reachable. This is done because, when using one of those methods, it is possible for the program to call an arbitrary method of any reachable type, dependent on input seen at runtime.
It is possible to determine if this degraded version of deadcode elimination is being used by examining the output of the `-dumpdep` flag of the linker. This can also be used to determine where the problem lies in a program with many dependencies.
In many cases these problematic reflection methods can be avoided without loss of functionality and without breaking backwards compatibility. I will show how to do this using the real world examples of three popular projects: Delve, Cobra and Starlark.