猜想:
书中第二章很多篇幅讲了加法操作,不禁让我思考计算机执行减法,又有什么不同?
假设没有减法操作,编译源代码的时候,会将减法,改成加法的指令,比如
(1)2-4 等价与 2+(-4)
(2)那如果都是无符号数呢 2u-4u 等价于什么?或者说(1)的结论就是错的,编译程序不会这样做,不会把减法改为加法
// 源代码 demo1.c
int main(){
unsigned char a = 2;
unsigned char b = 4;
unsigned char answer = a - b; // answer <=> [0x FD] <=> [1111 1110] <=> 254
}
// 获取汇编代码
// gcc demo1.c -o demo1.out
// objectdump -d demo1.out
00000000004004d6 <main>:
4004d6: 55 push %rbp
4004d7: 48 89 e5 mov %rsp,%rbp %rsp 栈指针,指向内存中的某个地址
4004da: c6 45 fd 02 movb $0x2,-0x3(%rbp) (1)将局部变量a=2 [0x 02]存到内存-0x3(%rbp)中
4004de: c6 45 fe 04 movb $0x4,-0x2(%rbp) (2)将局部变量b=4 [0x 04]存到内存-0x2(%rbp)中
4004e2: 0f b6 45 fd movzbl -0x3(%rbp),%eax (3)将a(即 0x 02)做零拓展为(0x 00 00 00 02) 存到%eax中,所以%al存储的是[0x 02]
4004e6: 2a 45 fe sub -0x2(%rbp),%al (4)sub 内存的-0x2(%rbp) 即[0x 04], 寄存器中的%al即[0x 02] 计算2-4并将结果存到%al
4004e9: 88 45 ff mov %al,-0x1(%rbp) (5)将计算结果存到内存-0x1(%rbp)中
4004ec: b8 00 00 00 00 mov $0x0,%eax
4004f1: 5d pop %rbp
4004f2: c3 retq
4004f3: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
4004fa: 00 00 00
4004fd: 0f 1f 00 nopl (%rax)
对比
// 源代码 demo2.out
int main(){
char a = 2;
char b = 4;
char answer = a - b; // answer <=> [0x FD] <=> [1111 1110] <=> -2
}
// 获取汇编代码
// gcc demo1.c -o demo2.out
// objectdump -d demo2.out
00000000004004d6 <main>:
4004d6: 55 push %rbp
4004d7: 48 89 e5 mov %rsp,%rbp
4004da: c6 45 fd 02 movb $0x2,-0x3(%rbp)
4004de: c6 45 fe 04 movb $0x4,-0x2(%rbp)
4004e2: 0f b6 55 fd movzbl -0x3(%rbp),%edx 2
4004e6: 0f b6 45 fe movzbl -0x2(%rbp),%eax 4
4004ea: 29 c2 sub %eax,%edx sub 4, 2 (这里直接寄存器取值,做减法,有点意思,跟上面那个例子又不太一样)
4004ec: 89 d0 mov %edx,%eax
4004ee: 88 45 ff mov %al,-0x1(%rbp)
4004f1: b8 00 00 00 00 mov $0x0,%eax
4004f6: 5d pop %rbp
4004f7: c3 retq
4004f8: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
4004ff: 00
解析:
从第(4)步中,可以看到,sub x, y 指令对于给他的两个操作数
不管给它的操作数是无符号还是有符号,执行的都是同样的电路操作
同时也验证了猜想的不合理
思考:
参考