您不调用内核内部的函数。内核位于另一个特权级别;普通代码无法访问其内存页面。为了跳入内核代码,应用程序代码执行一个系统调用,这需要使用一个特定的门来处理临时权限提升。在运行 Linux 的 32 位 x86 系统上,这是通过int 0x80
:软件触发的中断来完成的。系统调用参数由调用者在一些特定的CPU寄存器中提供;特别是,%eax
寄存器包含应用程序想要执行的系统调用的符号标识符。中断处理程序(在内核中)查看 CPU 寄存器以了解应用程序希望内核做什么(系统调用是否授予是另一个问题)。
系统调用没有 ASLR;这不是一个相关的概念。ASLR 用于DLL。DLL 是加载到应用程序地址空间的一段应用程序代码,应用程序可以在其正常权限下访问;特别是,应用程序代码可以通过正常的“跳转”操作码“跳转”到 DLL 代码中(函数调用只不过是一种美化的跳转)。
由于只有在实际加载 DLL 时才能知道加载 DLL 的实际地址,因此应用程序代码遵循特殊约定,以便可以动态调整其跳转操作码以指向恰好加载 DLL 的位置。这种动态调整由动态链接器执行。该链接器使用重定位表来执行其工作:此类表中的条目描述了需要调整的操作码,以及操作码尝试访问的函数的名称。当 DLL 被加载(通过动态链接器)时,该函数在内存中的位置是已知的,并且重定位表中描述的跳转操作码被调整。
如您所见,DLL 的整个概念允许将 DLL 加载到 RAM 中的任意位置。该位置可能会随着应用程序的连续执行而有所不同。实际位置取决于哪里有足够大的可用内存“洞”来进行加载,因此它可以根据应用程序的操作、之前分配的内存量等而改变。DLL 加载“自然”意味着非固定加载地址。ASLR只是DLL 的自愿移动:动态链接器有意选择一个随机(免费)加载地址。这对应用程序(几乎)是完全透明的。