Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Semantics of __imp_ symbols

Calling DLL functions involves the linker generating a stub, unless the function was declared __declspec(dllimport) in which case the stub can be bypassed in favor of an indirect call straight to the import table which is slightly more efficient, e.g.

__declspec(dllimport) void ExitProcess(int);
ExitProcess(0);

generates

call qword ptr [__imp_ExitProcess]

where __imp_ExitProcess resolves to a location in the import table in the executable.

I'm trying to figure out exactly how __imp_ExitProcess is resolved. It occurs as a symbol in kernel32.lib to be sure, but that symbol has storage class IMAGE_SYM_CLASS_EXTERNAL, section number zero and value zero, which amounts to just saying 'this will be defined somewhere else' without actually ever defining it.

Does the __imp_ prefix have special meaning, i.e. does the linker notice that prefix and take it as an instruction to resolve the symbol to the import table entry for the DLL function whose name has that prefix removed? Or is something else going on?

like image 804
rwallace Avatar asked Dec 25 '22 11:12

rwallace


2 Answers

The linker adds to your program a function like:

void (*__imp_ExitProcess)(int) = ...;

void ExitProcess(int n)
{
    return (*__imp_ExitProcess)(n);
}

where __imp_ExitProcess points to the "real" ExitProcess in KERNEL32.DLL.

Declaring this in your code:

__declspec(dllimport) void ExitProcess(int);

is equivalent to:

extern void (*__imp_ExitProcess)(int);

#define ExitProcess (*__imp_ExitProcess)

except that __declspec(dllimport) is handled by the compiler, not by the preprocessor.

like image 120
Hobbes Avatar answered Dec 28 '22 01:12

Hobbes


Just came up with a test that gives a data point. The following program:

__declspec(dllimport) void ExitProcess(int);

void __imp_ExitProcess(int x) {
}

int main() {
    ExitProcess(0);
}

crashes when compiled with the Microsoft compiler and run (but runs okay if the empty function is renamed to anything else); thus, it seems the linker behaves as though the __imp_ name is special, at least in the sense that a linker that behaves that way will generate a correct executable in all cases where the Microsoft linker does so, unless I'm missing something.

like image 40
rwallace Avatar answered Dec 28 '22 02:12

rwallace