Skip to content

Commit 3313799

Browse files
authored
Merge pull request #2864 from corob-msft/cr-2029
Address 2029, why no import table under /GL
2 parents c2500fc + 8caf6e8 commit 3313799

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

docs/build/importing-function-calls-using-declspec-dllimport.md

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
---
2-
title: "Importing Function Calls Using __declspec(dllimport)"
3-
ms.date: "11/04/2016"
2+
title: "Importing function calls using __declspec(dllimport)"
3+
description: "How and why to use __declspec(dllimport) when calling DLL data and functions."
4+
ms.date: "05/03/2020"
45
helpviewer_keywords: ["importing function calls [C++]", "dllimport attribute [C++], function call imports", "__declspec(dllimport) keyword [C++]", "function calls [C++], importing"]
56
ms.assetid: 6b53c616-0c6d-419a-8e2a-d2fff20510b3
67
---
7-
# Importing Function Calls Using __declspec(dllimport)
8+
# Importing function calls using `__declspec(dllimport)`
89

9-
The following code example shows how to use **_declspec(dllimport)** to import function calls from a DLL into an application. Assume that `func1` is a function that resides in a DLL separate from the .exe file that contains the **main** function.
10+
Annotating calls by using the **`__declspec(dllimport)`** can make them faster. **`__declspec(dllimport)`** is always required to access exported DLL data.
1011

11-
Without **__declspec(dllimport)**, given this code:
12+
## Import a function from a DLL
1213

13-
```
14+
The following code example shows how to use **`__declspec(dllimport)`** to import function calls from a DLL into an application. Assume that `func1` is a function that's in a DLL separate from the executable file that contains the **main** function.
15+
16+
Without **`__declspec(dllimport)`**, given this code:
17+
18+
```C
1419
int main(void)
1520
{
1621
func1();
@@ -19,29 +24,29 @@ int main(void)
1924
2025
the compiler generates code that looks like this:
2126
22-
```
27+
```asm
2328
call func1
2429
```
2530

2631
and the linker translates the call into something like this:
2732

28-
```
33+
```asm
2934
call 0x4000000 ; The address of 'func1'.
3035
```
3136

32-
If `func1` exists in another DLL, the linker cannot resolve this directly because it has no way of knowing what the address of `func1` is. In 16-bit environments, the linker adds this code address to a list in the .exe file that the loader would patch at run time with the correct address. In 32-bit and 64-bit environments, the linker generates a thunk of which it does know the address. In a 32-bit environment the thunk looks like:
37+
If `func1` exists in another DLL, the linker can't resolve this address directly because it has no way of knowing what the address of `func1` is. In 32-bit and 64-bit environments, the linker generates a thunk at a known address. In a 32-bit environment the thunk looks like:
3338

34-
```
39+
```asm
3540
0x40000000: jmp DWORD PTR __imp_func1
3641
```
3742

38-
Here `imp_func1` is the address for the `func1` slot in the import address table of the .exe file. All the addresses are thus known to the linker. The loader only has to update the .exe file's import address table at load time for everything to work correctly.
43+
Here `__imp_func1` is the address for the `func1` slot in the import address table of the executable file. All these addresses are known to the linker. The loader only has to update the executable file's import address table at load time for everything to work correctly.
3944

40-
Therefore, using **__declspec(dllimport)** is better because the linker does not generate a thunk if it is not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.
45+
That's why using **`__declspec(dllimport)`** is better: because the linker doesn't generate a thunk if it's not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.
4146

4247
So now this code:
4348

44-
```
49+
```C
4550
__declspec(dllimport) void func1(void);
4651
int main(void)
4752
{
@@ -51,13 +56,13 @@ int main(void)
5156
5257
generates this instruction:
5358
54-
```
59+
```asm
5560
call DWORD PTR __imp_func1
5661
```
5762

58-
There is no thunk and no `jmp` instruction, so the code is smaller and faster.
63+
There's no thunk and no `jmp` instruction, so the code is smaller and faster. You can also get the same effect without **`__declspec(dllimport)`** by using whole program optimization. For more information, see [/GL (Whole Program Optimization)](reference/gl-whole-program-optimization.md).
5964

60-
On the other hand, for function calls inside a DLL, you do not want to have to use an indirect call. You already know a function's address. Because time and space are required to load and store the address of the function before an indirect call, a direct call is always faster and smaller. You only want to use **__declspec(dllimport)** when calling DLL functions from outside the DLL itself. Do not use **__declspec(dllimport)** on functions inside a DLL when building that DLL.
65+
For function calls within a DLL, you don't want to have to use an indirect call. The linker already knows the function's address. It takes extra time and space to load and store the address of the function before an indirect call. A direct call is always faster and smaller. You only want to use **`__declspec(dllimport)`** when calling DLL functions from outside the DLL itself. Don't use **`__declspec(dllimport)`** on functions inside a DLL when building that DLL.
6166

6267
## See also
6368

0 commit comments

Comments
 (0)