According to gABI: First, all of the non-default visibility attributes, when applied to a symbol reference, imply that a definition to satisfy that reference must be provided within the current executable or shared object. If such a symbol reference has no definition within the component being linked, then the reference must have STB_WEAK binding and is resolved to zero. it is ok to have extern int short_hidden_ref_norm_def __attribute__ ((visibility ("hidden"))); int main() { printf ("%d\n", short_hidden_ref_norm_def); return 0; } But gcc 3.2.1-7 doesn't make short_hidden_ref_norm_def as hidden.
That's on purpose. When you use visibility attribute on an external, you guarantee that either you use the same attribute on the symbol definition, or that you make the symbol .hidden in some other way (e.g. in assembly). Initially, visibility attribute added .hidden even for external references, but that created more problems than it was worth, so it was changed this way.
I believe the bug is in ld, not gcc. I am working on ld to make it compliant to gABI. Right now, ld doesn't follow gABI.
The gABI allows weak undefined hidden/protected symbols. Visibility information may also help linker. Gcc emits weak undefined symbols. I think it should do the same for hidden/protected symbols.