当我看到用C / C ++编写的代码的反汇编时,我总觉得这很令人困惑。
有一个有一定价值的寄存器。我想知道它是代表签名号码还是无符号号码。我怎么能找到这个?
我的理解是,如果它是有符号整数,如果它是负数,则将设置MSB,如果它是正数则不设置。如果我发现它是无符号整数,则MSB无关紧要。这是对的吗?
无论如何,这似乎没有帮助:在我可以使用此信息之前,我仍然需要确定整数是否已签名。怎么办呢?
答案 0 :(得分:7)
你最好的选择是寻找比较和相关动作/标志用法,如分支。根据类型,编译器将生成不同的代码。由于大多数(相关)体系结构提供了处理签名值的标志。以x86为例:
jg, jge, jl, jle = branch based on a signed comparison (They check for the SF flag)
ja, jae, jb, jbe = branch based on a unsigned comparison (They check for the CF flag)
对于签名/未签名操作,CPU上的大多数指令都是相同的,因为我们现在使用的是Two's-Complement表示。但也有例外。
让我们以右移为例。使用X86上的无符号值,您可以使用SHR将某些内容向右移动。这将在左侧的每个“新创建的位”上添加零。
但对于有符号值,通常会使用SAR,因为它会将MSB扩展为所有新位。这就是所谓的“符号扩展”,并且只能使用,因为我们正在使用Two's-Complement。
最后但并非最不重要的是,对签名/无符号乘法/除法有不同的指令。
imul+idiv = signed
mul+div = unsigned
如评论中所述,imul是一种特殊情况,因为它也可以用于无符号乘法。唯一的区别在于正在设置的标志。所以,如果你看到一个带有值的imul,就不要太信任代码,这取决于具体情况。
NEG指令通常只用于有符号值,因为它是一个二进制补码否定。
答案 1 :(得分:4)
一般情况下,你将无法做到。对于有符号值或无符号值,发生在积分值上的许多事情都会以相同的方式发生。例如,分配。要告诉的唯一方法是代码是否正在进行算术运算。通过观察价值你绝对无法分辨;所有可能的位模式都有效。
答案 2 :(得分:2)
在大多数处理器中(至少那些使用二进制补码数学的处理器),存储在寄存器或存储器中的整数没有固有的符号。解释取决于使用的说明。简短摘要:
加法和减法为有符号和无符号数字生成完全相同的位模式,因此通常没有符号加法或减法。 (Hovewer,MIPS有单独的指令,如果操作溢出则会导致陷阱)。
除法和乘法确实会对有符号和无符号数产生不同的结果,因此如果处理器支持它,它们会成对出现(x86:mul / imul,div / idiv)。
条件分支也可能根据比较结果的解释而不同(通常实现为减法)。例如,在x86上,签名更高 jg
,签名
请注意,浮点数(符合IEEE格式)使用显式符号位,因此上述内容不适用于它们。
答案 3 :(得分:0)
除了已经说过的内容之外,查看运行时值也可以提供帮助。
例如,在
中add eax, edx ; eax = 0xFFFFFFF0, edx = 100
eax
可能包含已签名的变量。这里没有任何保证,但在任何地方都没有保证 - 代码总是有可能完全错误。存在(有意或无意)无符号溢出的代码,但实际上它更有可能被解释为有符号的非溢出。