在项目中遇到一个奇怪的宕机问题,后来查询定位发现是erlang底层数据溢出问题,用c模拟情况类似,当一个int类型的x值大于等于1<<25的时候,再左移6位会造成nt溢出,然后再强转成64位无符号整数。
test_int.c
#include <stdio.h> int main(){ int a = 1; int x = (a<<25); int x1 = (x<<6)+10; unsigned long y = (unsigned long)(x1); y+=1; y+=1; y+=1; y+=1; printf("x=%d/n", x); printf("x1=%d/n", x1); printf("y=%lu/n", y); return 0; }
输出结果
x=33554432 x1=-2147483638 y=18446744071562067982
gcc -S test_int.c
subq $32, %rsp movl $1, -4(%rbp) --- - -4(%rbp)表示a movl -4(%rbp), %eax sall $25, %eax movl %eax, -8(%rbp) ----- -8(%rbp) 表示 x movl -8(%rbp), %eax sall $6, %eax addl $10, %eax movl %eax, -12(%rbp) ---- -12(%rbp) 表示x1 movl -12(%rbp), %eax ------ 这里开始符号扩展 cltq movq %rax, -24(%rbp) addq $1, -24(%rbp) addq $1, -24(%rbp) addq $1, -24(%rbp) addq $1, -24(%rbp) movl -8(%rbp), %eax movl %eax, %esi
顺带再分析了一下32位有符号数转换成64位无符号数的时候在底层汇编会发生什么。
有符号数在底层都是用补码进行表示,转换成无符号数的时候需要根据最高位进行判断,最高位是1的话则用1来扩充,是0的话用0扩充。
cltq就是符号扩展指令,只对eax寄存器扩展到rax寄存器。
原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/245414.html