GlobalLock
/ GlobalUnlock
and LockResource
/ FreeResource
preserved in Win32API for compatibility with those dense times, although in Win32 memory blocks (including resources) were never moved.
LockSegment
and UnlockSegment
(fix / free memory at the address, not the handle) remained for some time in the documentation marked “obsolete, do not use”, but now they don’t even have any memories left.
GlobalWire
function - “so that the unit does not GlobalWire
out in the middle of the address space, move it to the lower edge of the memory and fix it there”; GlobalUnwire
, completely equivalent to GlobalUnwire
, corresponded to GlobalUnlock
. This pair of functions, surprisingly, is still alive in kernel32.dll, although they have already been removed from the documentation. Now they just call GlobalLock
/ GlobalUnlock
.
GlobalLock
function GlobalLock
replaced with a “stub”: now Windows can shuffle the memory blocks without changing their “virtual address” visible to the application (selector: offset) - which means that the application no longer needs to fix non-paged objects. In other words, fixing now prevents unloading of the block, but does not prevent its (imperceptible for the application) movement. Therefore, in order to fix the data “in reality” in physical memory, for those who need exactly this (for example, to work with external devices), a pair of GlobalFix
/ GlobalUnfix
. Just like GlobalWire
/ GlobalUnwire
, in Win32, these functions have become useless; and they are also removed from the documentation in the same way, although they remain in kernel32.dll, and they call GlobalLock
/ GlobalUnlock
.
LockFunction
before each function call; but recall that many functions twist the “message loop”, for example, show a window or execute DDE commands, - and they could also be unloaded for this time, because in fact, their code is not needed at this time. However, when using "function handles," the function segment will not be released until it returns control to the calling function.
BP
pointer to the frame of the calling function. (Since the stack consists of 16-bit words, the BP
value is always even.) In addition, Windows should distinguish between intra-segment (“close”) and inter-segment (“far”) calls in the stack, and can ignore close calls — they’re don't exactly lead to the unloaded segment. Therefore, it was decided that the odd BP
value in the stack means a far call, i.e. each distant function must begin with the pr-pr- INC BP; PUSH BP; MOV BP,SP
INC BP; PUSH BP; MOV BP,SP
INC BP; PUSH BP; MOV BP,SP
and end with the epilogue of POP BP; DEC BP; RETF
POP BP; DEC BP; RETF
POP BP; DEC BP; RETF
(In fact, the prologue and epilogue were more difficult , but this is not about that now.)
int 3fh
instruction, and three more service bytes indicating where to look for the function. The int 3fh
finds these service bytes at its return address; determines the desired segment; loads it into memory if it is not already loaded; and finally overwrites the stub in the input table with an absolute jmp xxxx:yyyy
transition to the function body, so that the next calls to this function are slowed down only by one intersegment transition, without interruption.
int 3fh
stub in the module's input table. The system has no need to look for all the calls of the unloaded function - they were all found during compilation! The module’s “input table” lists all distant functions that the compiler knows about the existence of intersegmental calls (this includes, for example, exported functions and WinMain
), as well as all distant functions that were passed somewhere along the pointer, which means called from anywhere, even from outside the program code (this includes WndProc
, EnumFontFamProc
and other callback functions).
GetWindowLong(GWL_WNDPROC)
and similar calls also point to the stub, and not to the function body. Even GetProcAddress
tricky, and instead of the address of the function, it returns the address of its stub in the DLL input table. (In Win32, only the DLL entry analogue of the “input table” remained, called the “export table”.) Static intermodule calls (calls to functions imported from a DLL) are resolved using the same GetProcAddress
, and therefore exactly the same cause a stub . In any case, it turns out that when unloading a function, it is enough to fix the stub, and you do not need to touch the calling code itself.
int 3fh
or jmp
replacing it) the sar byte ptr cs:[xxx], 1
instruction sar byte ptr cs:[xxx], 1
which resets the byte-counter from 1 to 0 with each function call. This instruction just takes five bytes: you can save the existing format of the executable file, and load the int 3fh
through one, interspersed with the instruction counter.
GlobalLock
or similar functions. So when it comes time to unload a segment in order to free up memory - Windows will try to unload the segment to which it has not been accessed for the longest: either the code segment whose counter has not been reset to 0 for the longest, or the data segment that has not been for the longest was fixed.
Source: https://habr.com/ru/post/154713/