The linker generates go.info.* symbols for Go types. It does so by parsing the contents of type.* symbols. It also depends on the names of these type.* symbols to successfully find other others.
All of this makes the linker quite fragile. The logic in decodesym.go has to be kept in sync with the compiler's rtype code generation, the runtime, and the reflect package. Depending on the type. symbol names interacts poorly with other things the linker wants to do, like rename symbols.
An easier place to generate these go.info.* symbols is in the compiler, right next to the code that generates the type.* symbols. The data structures are all nicely laid out in memory and don't require the hairy partial-decoding we do in the linker.
It looks like a tiny part of this has already been done, the compiler generates go.info symbols for vars. It should be possible to move the rest of the type symbols to the compiler piecemeal.
I think this would be nice, and might incidentally help with #21945 by giving us a CU per package, but I don't see an overwhelming benefit here. Maybe I'm missing something.
decodesym.go seems to be a bit of a grab bag; some of its functions are only used by the DWARF generation, but others are only used in dead code elimination, and others are used in other parts of the linker. Seems unlikely we'll ever delete the code wholesale, though.
Can you give an example of a case where this has given us trouble? Most of it hasn't changed in a solid year other than your recent refactorings.
I wonder how many redundant type DIEs we'd end up creating, and how much of a performance impact that would have on the linker. Packages should carry DIEs for types they declare, and we can interpret strings and such as being in the runtime package, so those can be referenced rather than recreated. What about maps and other derived types? I guess we can do whatever we do for their alg functions.