我是x86的新手。我的问题是关于函数调用。据我所知,有三种函数调用类型:短调用(0xe8),远调用(0x9a)和近调用(0x ??)。有些呼叫短呼叫一个相对呼叫(ip + = arg / cs = inv)并远远调用绝对呼叫(ip = arg / cs = arg),但接近呼叫(ip =?/ cs =?)怎么样。有人说在32位系统上调用函数far(9a)几乎肯定是错误的。为什么? x86不代表32位系统吗? far call的参数是一个扁平的地址(我们在c ++或其他语言中使用的那个)或cs:ip notated以及如何将普通地址转换为cs:ip form?还有其他函数调用类型吗?
答案 0 :(得分:7)
CALL
指令的类型是:
call func
)call 0x12:0x12345678
)call [edi]
)call far [edi]
)远程调用意味着除了cs
之外,它还会更改段选择器(eip
)的值。近来通话仅更改ip
/ eip
/ rip
。
相对意味着地址将相对于下一条指令的地址,而绝对调用则提供跳转到的确切地址。
间接调用指定寄存器或存储器内容中的目标地址,而在直接调用中,它将被指定为指令的一部分。
有人说在32位系统上调用函数far(9a)几乎肯定是错误的。为什么呢?
可能是因为通常32位操作系统将使用平面内存模型,其中所有内存都可以从同一段访问(如果允许访问),因此无需更改cs
的值。
远call
也推送CS:EIP而不仅仅是EIP作为返回地址,如果你调用一个正常的函数来预期在返回地址正上方找到堆栈参数,这就是一个问题。
x86不是指32位系统吗?
没有。 x86最初是一个16位指令集,后来扩展到32位然后扩展到64位。另请参阅Stack Overflow的x86 tag wiki
far call的参数是一个普通地址(我们在c ++或其他语言中使用的那个)或cs:ip notated以及如何将普通地址转换为cs:ip form?
我不知道你所说的“普通地址”是什么意思。在具有平坦内存模型的32位操作系统上,存储在C ++指针中的地址不包含段选择器,因此要将其转换为远地址,您需要添加cs
的值。
但是对于绝对直接形式,你需要在建立时cs
得到正确的值。