The indirect jump instruction must be generated by the linker because the compiler doesn't know the function will turn out to be in a DLL.
Actually, this is not always the case. If you mark the function with __declspec(dllimport)
, the compiler does know it will be a DLL import and in that case it can generate an indirect call:
; HMODULE = LoadLibrary("mylib");
push offset $SG66630
call [__imp__LoadLibraryA@4]
(__imp__LoadLibraryA@4
is the pointer to the import in the IAT)
If you do not use dllimport
then the compiler generates a relative function call:
push offset $SG66630
call _LoadLibraryA@4
And in such case the linker has to generate a jump stub:
LoadLibraryA proc near
jmp [__imp__LoadLibraryA@4]
LoadLibraryA endp
And, in fact, it does group such jump stubs together (though possibly by compile unit and/or imported DLL, not 100% sure here).
Note: in the past, the linker did not explicitly generate jump stubs but took them from the import libraries. They contained complete object files both the stubs and the structures necessary for generating the PE import directory. See this article for how it all worked: https://www.microsoft.com/msj/0498/hood0498.aspx
These days the import libraries have only the API and DLL names and the linker knows how to generate the necessary code and metadata for importing them.