Ada*_*ner 4 architecture memory encoding function computer-architecture
我理解数字和字母之类的东西是用二进制编码的,因此可以存储为0和1.
但是如何将函数存储在内存中?我不知道如何将它们存储为0和1,并且我不知道除了0和1以外什么东西可以存储在内存中.
Dou*_*gvj 15
它们实际上存储在0和1的内存中
这是一个真实世界的例子:
int func(int a, int b) {
return (a + b);
}
Run Code Online (Sandbox Code Playgroud)
以下是编译器可能为该函数生成的32位x86机器指令的示例(以文本表示形式称为汇编代码):
func:
push ebp
mov ebp, esp
mov edx, [ebp+8]
mov eax, [ebp+12]
add eax, edx
pop ebp
ret
Run Code Online (Sandbox Code Playgroud)
了解这些指令的工作方式超出了本问题的范围,但这些符号中的每一个(例如add,pop,mov等)及其参数都被编码为1和0.此表显示了许多英特尔指令以及它们如何编码的摘要.另请参阅x86标记wiki以获取文档/指南/手册的链接.
那么如何将代码从文本汇编转换为机器可读字节(又称机器代码)呢?举例来说,指令add eax, edx.此页面显示了如何编码添加指令. eax和edx是一种称为寄存器的东西,处理器中的物理点用于保存信息以进行处理.计算机编程中的变量通常会在某些时候映射到寄存器.因为我们正在添加寄存器并且寄存器是32位,所以我们选择操作码000000001(另请参阅英特尔的ADD官方指令集参考手册,其中列出了所有可用的表格).
下一步是指定操作数.上一页的这一部分显示了如何使用与我们自己非常相似的示例"add ecx,eax"来完成此操作.前两位必须为'11'才能显示我们正在添加寄存器.接下来的3位指定第一个寄存器,在我们的例子中,我们选择edx而不是他们示例中的eax,这使得我们得到'100'.接下来的3位指定了我们的eax,所以我们得到了最终的结果
00000001 11100000
Run Code Online (Sandbox Code Playgroud)
这是十六进制的01 D0.可以应用类似的过程将任何指令转换为二进制.用于自动执行此操作的工具称为汇编程序.
因此,通过汇编程序运行上面的汇编代码会产生以下输出:
66 55 66 89 E5 66 67 8B 55 O8 66 67 8B 45 0C 66 01 D0 66 5D C3
Run Code Online (Sandbox Code Playgroud)
注意01 D0字符串末尾附近,这是我们的"添加"指令.将机器代码字节转换回文本汇编语言助记符称为反汇编:
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
Run Code Online (Sandbox Code Playgroud)
地址从零开始,因为这只是一个.o,而不是链接的二进制文件.所以他们只是相对于文件.text部分的开头.
你可以在Godbolt编译器资源管理器上看到你喜欢的任何函数(或者你自己的机器上任何二进制文件,新编译或不使用反汇编程序).
您可能会注意到最终输出中没有提到名称"func".这是因为在机器代码中,函数由其在RAM中的位置引用,而不是其名称.编译器输出目标文件func的符号表中可能有一个引用此机器代码块的条目,但符号表由软件读取,而不是CPU硬件可以直接解码和运行的内容. 机器代码的位模式由CPU中的晶体管直接看到和解码.
有时我们很难理解计算机如何在低级别编码这样的指令,因为作为程序员或高级用户,我们有工具可以避免直接处理它们.我们依靠编译器,汇编器和解释器为我们工作.尽管如此,计算机所做的任何事情最终都必须在机器代码中指定.
编辑:解释从指令到操作码的精确转换过程.
| 归档时间: |
|
| 查看次数: |
3063 次 |
| 最近记录: |