TL;DR: load global variables into local ones before use.
I've spotted a quite widespread misuse of global pointer variables. The issue is easily demonstrated by the following simplified example.
struct some_type_t {
int a1;
int a2;
int a3;
};
struct some_type_t *p_global;
void f1()
{
p_global->a1 = 1;
p_global->a2 = 2;
p_global->a3 = 3;
}
void f2()
{
struct some_type_t *t_global = p_global;
t_global->a1 = 1;
t_global->a2 = 2;
t_global->a3 = 3;
}
Which gets compiled into the following, using MSVC 2010:
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
TITLE C:\Users\User\Projects\test.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES
_DATA SEGMENT
COMM _p_global:DWORD
_DATA ENDS
PUBLIC _f1
; Function compile flags: /Ogtpy
; File c:\users\user\projects\test.c
; COMDAT _f1
_TEXT SEGMENT
_f1 PROC ; COMDAT
; 12 : p_global->a1 = 1;
00000 a1 00 00 00 00 mov eax, DWORD PTR _p_global
00005 c7 00 01 00 00
00 mov DWORD PTR [eax], 1
; 13 : p_global->a2 = 2;
0000b 8b 0d 00 00 00
00 mov ecx, DWORD PTR _p_global
00011 c7 41 04 02 00
00 00 mov DWORD PTR [ecx+4], 2
; 14 : p_global->a3 = 3;
00018 8b 15 00 00 00
00 mov edx, DWORD PTR _p_global
0001e c7 42 08 03 00
00 00 mov DWORD PTR [edx+8], 3
; 15 : }
00025 c3 ret 0
_f1 ENDP
_TEXT ENDS
PUBLIC _f2
; Function compile flags: /Ogtpy
; COMDAT _f2
_TEXT SEGMENT
_f2 PROC ; COMDAT
; 19 : struct some_type_t *t_global = p_global;
00000 a1 00 00 00 00 mov eax, DWORD PTR _p_global
; 20 : t_global->a1 = 1;
00005 c7 00 01 00 00
00 mov DWORD PTR [eax], 1
; 21 : t_global->a2 = 2;
0000b c7 40 04 02 00
00 00 mov DWORD PTR [eax+4], 2
; 22 : t_global->a3 = 3;
00012 c7 40 08 03 00
00 00 mov DWORD PTR [eax+8], 3
; 23 : }
00019 c3 ret 0
_f2 ENDP
_TEXT ENDS
END
Moral of the story is quite obvious: loading the variable from global to local allows the compiler to shave off reloads on each use -- as it can't infer the global won't change between uses.
And now for a real life example:
INIT:BFA33B6C ; =============== S U B R O U T I N E =======================================
INIT:BFA33B6C
INIT:BFA33B6C
INIT:BFA33B6C ; _DWORD __stdcall InitFunctionTables()
INIT:BFA33B6C _InitFunctionTables@0 proc near ; CODE XREF: Win32UserInitialize()+1EE�p
INIT:BFA33B6C mov eax, _gpsi
INIT:BFA33B71 mov dword ptr [eax+88h], offset _xxxSBWndProc@16 ; xxxSBWndProc(x,x,x,x)
INIT:BFA33B7B mov ecx, _gpsi
INIT:BFA33B81 mov eax, offset _xxxDefWindowProc@16 ; xxxDefWindowProc(x,x,x,x)
INIT:BFA33B86 mov [ecx+8Ch], eax
INIT:BFA33B8C mov ecx, _gpsi
INIT:BFA33B92 mov dword ptr [ecx+90h], offset _xxxMenuWindowProc@16 ; xxxMenuWindowProc(x,x,x,x)
INIT:BFA33B9C mov ecx, _gpsi
INIT:BFA33BA2 mov dword ptr [ecx+94h], offset _xxxDesktopWndProc@16 ; xxxDesktopWndProc(x,x,x,x)
INIT:BFA33BAC mov ecx, _gpsi
INIT:BFA33BB2 mov [ecx+98h], eax
INIT:BFA33BB8 mov ecx, _gpsi
INIT:BFA33BBE mov [ecx+9Ch], eax
INIT:BFA33BC4 mov ecx, _gpsi
INIT:BFA33BCA mov eax, 0F8h
INIT:BFA33BCF mov [ecx+0A4h], ax
INIT:BFA33BD6 mov ecx, _gpsi
INIT:BFA33BDC add eax, 0FFFFFFB8h
INIT:BFA33BDF mov [ecx+0A6h], ax
INIT:BFA33BE6 mov ecx, _gpsi
INIT:BFA33BEC mov eax, 0B4h
INIT:BFA33BF1 mov [ecx+0A8h], ax
INIT:BFA33BF8 xor eax, eax
INIT:BFA33BFA
INIT:BFA33BFA loc_BFA33BFA: ; CODE XREF: InitFunctionTables()+A5�j
INIT:BFA33BFA mov edx, _gpsi
INIT:BFA33C00 mov ecx, eax
INIT:BFA33C02 and ecx, 1Fh
INIT:BFA33C05 inc eax
INIT:BFA33C06 mov dword ptr [edx+ecx*4+8], offset _EngSetPointerTag@20 ; EngSetPointerTag(x,x,x,x,x)
INIT:BFA33C0E cmp eax, 20h
INIT:BFA33C11 jb short loc_BFA33BFA
INIT:BFA33C13 mov eax, _gpsi
INIT:BFA33C18 mov dword ptr [eax+8], offset _xxxWrapSBWndProc@20 ; xxxWrapSBWndProc(x,x,x,x,x)
INIT:BFA33C1F mov ecx, _gpsi
INIT:BFA33C25 mov eax, offset _xxxWrapRealDefWindowProc@20 ; xxxWrapRealDefWindowProc(x,x,x,x,x)
INIT:BFA33C2A mov [ecx+0Ch], eax
INIT:BFA33C2D mov ecx, _gpsi
INIT:BFA33C33 mov dword ptr [ecx+10h], offset _xxxWrapMenuWindowProc@20 ; xxxWrapMenuWindowProc(x,x,x,x,x)
INIT:BFA33C3A mov ecx, _gpsi
INIT:BFA33C40 mov dword ptr [ecx+14h], offset _xxxWrapDesktopWndProc@20 ; xxxWrapDesktopWndProc(x,x,x,x,x)
INIT:BFA33C47 mov ecx, _gpsi
INIT:BFA33C4D mov [ecx+18h], eax
INIT:BFA33C50 mov ecx, _gpsi
INIT:BFA33C56 mov [ecx+1Ch], eax
INIT:BFA33C59 mov eax, _gpsi
INIT:BFA33C5E mov dword ptr [eax+64h], offset _xxxWrapSendMessage@20 ; xxxWrapSendMessage(x,x,x,x,x)
INIT:BFA33C65 mov eax, _gpsi
INIT:BFA33C6A mov dword ptr [eax+4Ch], offset _fnHkINLPCWPEXSTRUCT@20 ; fnHkINLPCWPEXSTRUCT(x,x,x,x,x)
INIT:BFA33C71 mov eax, _gpsi
INIT:BFA33C76 mov dword ptr [eax+50h], offset _fnHkINLPCWPRETEXSTRUCT@20 ; fnHkINLPCWPRETEXSTRUCT(x,x,x,x,x)
INIT:BFA33C7D mov eax, _gpsi
INIT:BFA33C82 mov dword ptr [eax+68h], offset _xxxSendMessageFF@20 ; xxxSendMessageFF(x,x,x,x,x)
INIT:BFA33C89 mov eax, _gpsi
INIT:BFA33C8E mov dword ptr [eax+6Ch], offset _xxxSendMessageEx@20 ; xxxSendMessageEx(x,x,x,x,x)
INIT:BFA33C95 mov eax, _gpsi
INIT:BFA33C9A mov dword ptr [eax+70h], offset _xxxWrapCallWindowProc@20 ; xxxWrapCallWindowProc(x,x,x,x,x)
INIT:BFA33CA1 mov eax, _gpsi
INIT:BFA33CA6 mov dword ptr [eax+74h], offset _xxxWrapSendMessageBSM@20 ; xxxWrapSendMessageBSM(x,x,x,x,x)
INIT:BFA33CAD mov eax, _gpsi
INIT:BFA33CB2 mov dword ptr [eax+20h], offset _xxxWrapSwitchWndProc@20 ; xxxWrapSwitchWndProc(x,x,x,x,x)
INIT:BFA33CB9 mov eax, _gpsi
INIT:BFA33CBE mov dword ptr [eax+7Ch], offset _xxxWrapSendNotifyMessage@20 ; xxxWrapSendNotifyMessage(x,x,x,x,x)
INIT:BFA33CC5 mov eax, _gpsi
INIT:BFA33CCA mov dword ptr [eax+80h], offset _xxxWrapSendMessageCallback@20 ; xxxWrapSendMessageCallback(x,x,x,x,x)
INIT:BFA33CD4 retn
INIT:BFA33CD4 _InitFunctionTables@0 endp