Относительный вызов используется для внутримодульных вызовов, хотя вызовы прямых адресов памяти, безусловно, возможны (это делается с помощью функций WinAPI):
FF15 B8401301 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf - note this calling with a pointer to the abs address stored in the IAT
Это происходит главным образом из-зачто Windows DLL не могут быть перераспределены (плюс они находятся в специальном адресном пространстве, так как каждое приложение имеет свой собственный «вид» системных DLL), но пользовательские DLL могут легко перераспределить (особенно с ASLR). см. Также статью в Википедии.
Кроме того, не путайте косвенные вызовы таблиц символов (так называемые интермодульные вызовы) с чисто относительными вызовами.если вы вызываете функции за пределами текущего модуля, вы получите относительный вызов к абсолютному адресу, хранящемуся в таблице символов:
CALL MySymb
MySymb: JMP &MySymbAbs
или лучшей, реальной версии:
6FC019E9 E8 300D0000 CALL <JMP.&Storm.#501> ; CALL 6FC0271E without name labeling
6FC0271E - FF25 8071C06F JMP DWORD PTR DS:[<&Storm.#501>] ; Storm.#501
Все это в значительной степени зависит и от вашего компилятора, некоторые могут делать прямые вызовы символов для всего, некоторые будут делать это только для системных библиотек и / или COM-интерфейсов.
Кстати, на32-битная x86, у вас технически нет 4 ГБ доступных в пользовательских приложениях, обычно это 3 ГБ.