32 位机器如何处理大于 2^32 的数字? [英] How are numbers greater than 2^32 handled by a 32 bit machine?
问题描述
我试图了解涉及大于 232 的数字的计算是如何在 32 位机器上发生的.
I am trying to understand how calculations involving numbers greater than 232 happen on a 32 bit machine.
C 代码
$ cat size.c
#include<stdio.h>
#include<math.h>
int main() {
printf ("max unsigned long long = %llu
",
(unsigned long long)(pow(2, 64) - 1));
}
$
gcc 输出
$ gcc size.c -o size
$ ./size
max unsigned long long = 18446744073709551615
$
对应的汇编代码
$ gcc -S size.c -O3
$ cat size.s
.file "size.c"
.section .rodata.str1.4,"aMS",@progbits,1
.align 4
.LC0:
.string "max unsigned long long = %llu
"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $-1, 8(%esp) #1
movl $-1, 12(%esp) #2
movl $.LC0, 4(%esp) #3
movl $1, (%esp) #4
call __printf_chk
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
$
第 1 - 4 行究竟发生了什么?
这是汇编级别的某种字符串连接吗?
Is this some kind of string concatenation at the assembly level?
推荐答案
__printf_chk
是 printf
的包装器,它检查堆栈溢出,并采用额外的第一个参数,一个标志(例如,参见 此处.)
__printf_chk
is a wrapper around printf
which checks for stack overflow, and takes an additional first parameter, a flag (e.g. see here.)
pow(2, 64) - 1
已优化为 0xffffffffffffffff
,因为参数是常量.
pow(2, 64) - 1
has been optimised to 0xffffffffffffffff
as the arguments are constants.
按照通常的调用约定,__printf_chk()
(int flag
) 的第一个参数是堆栈上的 32 位值(位于 %esp
在 call
指令时).下一个参数 const char * format
是一个 32 位指针(堆栈中的下一个 32 位字,即在 %esp+4
处).并且正在打印的 64 位数量占据接下来的两个 32 位字(在 %esp+8
和 %esp+12
处):
As per the usual calling conventions, the first argument to __printf_chk()
(int flag
) is a 32-bit value on the stack (at %esp
at the time of the call
instruction). The next argument, const char * format
, is a 32-bit pointer (the next 32-bit word on the stack, i.e. at %esp+4
). And the 64-bit quantity that is being printed occupies the next two 32-bit words (at %esp+8
and %esp+12
):
pushl %ebp ; prologue
movl %esp, %ebp ; prologue
andl $-16, %esp ; align stack pointer
subl $16, %esp ; reserve bytes for stack frame
movl $-1, 8(%esp) #1 ; store low half of 64-bit argument (a constant) to stack
movl $-1, 12(%esp) #2 ; store high half of 64-bit argument (a constant) to stack
movl $.LC0, 4(%esp) #3 ; store address of format string to stack
movl $1, (%esp) #4 ; store "flag" argument to __printf_chk to stack
call __printf_chk ; call routine
leave ; epilogue
ret ; epilogue
编译器有效地重写了这个:
The compiler has effectively rewritten this:
printf("max unsigned long long = %llu
", (unsigned long long)(pow(2, 64) - 1));
...进入这个:
__printf_chk(1, "max unsigned long long = %llu
", 0xffffffffffffffffULL);
...而且,在运行时,调用的堆栈布局如下所示(将堆栈显示为 32 位字,地址从图表底部向上增加):
...and, at runtime, the stack layout for the call looks like this (showing the stack as 32-bit words, with addresses increasing from the bottom of the diagram upwards):
: :
: Stack :
: :
+-----------------+
%esp+12 | 0xffffffff |
+-----------------+ } <-------------------------------------.
%esp+8 | 0xffffffff | / |
+-----------------+ |
%esp+4 |address of string| <---------------. |
+-----------------+ | |
%esp | 1 | <--. | |
+-----------------+ | | |
__printf_chk(1, "max unsigned long long = %llu
", |
0xffffffffffffffffULL);
这篇关于32 位机器如何处理大于 2^32 的数字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!