我知道像数字和字母这样的东西是如何以二进制编码的,因此可以存储为0和1。
但是函数如何存储在内存中呢?我不明白它们怎么能被存储为0和1,也不知道除了0和1之外,还有什么东西可以被存储在内存中。
我知道像数字和字母这样的东西是如何以二进制编码的,因此可以存储为0和1。
但是函数如何存储在内存中呢?我不明白它们怎么能被存储为0和1,也不知道除了0和1之外,还有什么东西可以被存储在内存中。
int func(int a, int b) {
return (a + b);
}
func:
push ebp
mov ebp, esp
mov edx, [ebp+8]
mov eax, [ebp+12]
add eax, edx
pop ebp
ret
本问题讨论每个指令如何工作超出范围,但其中每个符号(例如add、pop、mov等)及其参数都被编码为1和0。此表格展示了许多英特尔指令及其编码摘要。另请参阅x86标签维基以获取文档/指南/手册链接。
add eax, edx
为例。此页面展示了add指令的编码方式。eax和edx是一种叫做寄存器的东西,在处理器中用于保存信息进行处理。计算机编程中的变量通常在某个时刻映射到寄存器上。因为我们要添加寄存器,而这些寄存器是32位的,所以我们选择了操作码000000001(请参见英特尔官方指令集参考手册ADD条目,其中列出了所有可用的形式)。00000001 11100000
01 D0在十六进制中表示。将任何指令转换为二进制,可以应用类似的过程。自动执行此操作的工具称为汇编器。
66 55 66 89 E5 66 67 8B 55 O8 66 67 8B 45 0C 66 01 D0 66 5D C3
01 D0
,这是我们的“add”指令。将机器码字节转换回文本汇编语言助记符称为反汇编: address | machine code | disassembly
0: 55 push ebp
1: 89 e5 mov ebp, esp
3: 8b 55 08 mov edx, [ebp+0x8]
6: 8b 45 0c mov eax, [ebp+0xc]
9: 01 d0 add eax, edx
b: 5d pop ebp
c: c3 ret
.o
文件,而不是链接的二进制文件。因此,它们只是相对于文件的.text
部分的起始位置。objdump -drwC -Mintel
中获取。例如像这个x86机器码的codegolf答案一样。Godbolt编译器浏览器为gcc / clang / icc输出提供了显示此内容的二进制模式。 - Peter Cordes我将以最简单的方式解释函数是如何存储的。在本文的结尾,您会惊讶于这一切的惊人简单性。这是最基本的解释,任何类型的计算机都会以某种方式工作。
计算机中唯一能够对数据执行任何操作(例如加法、减法、乘法和除法)的部分。人类存在的所有数据操作(任何类型的数学或公式)都由这些操作组成。
现在让我们来看看二进制指令的基本结构。如果我们正在使用32位机器,则指令将采取以下形式:
1 001 32位地址 32位地址
1(如果此位为1,则将指令转移到逻辑单元进行计算;如果为零,则基本上在两个内存地址之间移动数据)001(这3位确定我们在此指令周期中是添加(001)、减去(010)、乘(011)还是除(100))(第一个内存位置的32位内存地址)(第二个内存地址的32位内存地址)
函数基本上是一系列指令的字符串,用于操作定义的内存位置中的数据。
让我们来看一个随机函数,它先加一个数字,然后再乘。它的指令字符串将是:
(让我用MA表示内存地址)
1 001 MAone MAtwo (将MAone中的值加上MAtwo中的值,并将结果存储在MAone中)
1 011 MAtwo MAthree (将MAtwo中的值乘以MAthree中的值,并将结果存储在MAthree中)
返回MAthree中的值
因此,函数存储的唯一区别是它们在最左边的位上带有1,以便CPU知道它是需要逻辑操作的函数,并将其转向ALU。
pext
/ pdep
)也是单独的原始操作,不便宜模拟。 - Peter Cordesvolatile
或atomic
的共享内存。) - Peter Cordes