c - 编译后的 c 可执行文件如何知道如何表示特定内存地址处的一系列位?
问题描述
我知道在编译期间 C 变量被替换为内存地址,并且带有类型信息的符号表无法在编译后继续存在。
我试图了解在编程执行期间如何存储和检索(表示)数据。我了解变量映射到内存地址,并且我的预编译代码指定了类型(位数以及如何读取它们)。但是,如果在代码编译成可执行文件时类型丢失了,机器代码(.exe)如何知道特定内存地址的数据大小以及如何表示这些位?
我见过许多类似的问题,但答案总是被认为 CPU 不关心或不知道这些位系列打算代表什么。然而,这并不是我要问的。我想知道可执行程序如何知道重要的位数以及如果类型(整数、字符、双精度、字符串或位字段)未知,如何读取(表示)它们?
解决方案
编译器生成机器指令,专门执行它想要的操作。(这可以分多个步骤完成,用编译器自己的语言生成中间代码,然后将其转换为汇编语言,然后将其汇编为机器指令。)
机器指令有特定的形式,例如:
- 从地址 1234 加载 32 位到寄存器 8
- 将寄存器 7 中的 64 位存储到地址 4320 中。
- 从当前程序计数器之外 9000 字节的内存中将 32 位加载到寄存器 3 中。
- 将寄存器 4 中的 8 位存储到堆栈指针之外 124 字节的内存中。
- 从寄存器 3 添加到寄存器 4。
- 比较寄存器 3 和寄存器 4。
- 如果最后一个比较指示有符号大于,则分支。
- 将寄存器 4 的内容右移 5 位(“逻辑上”,填充零)。
- 将寄存器 4 的内容右移 5 位(“算术”,复制符号位)。
因此,如果您的程序正在读取一个char
值,编译器会生成一条指令来加载 8 位。如果您的程序正在读取一个int
值,编译器会生成一条指令来加载 32 位(假设int
在您的 C 实现中是 32 位)。
在许多指令中,处理器不需要知道数据类型是什么。加载 32 位就是加载 32 位,无论这些位是int
指针还是指针。即使在添加有符号或无符号整数时,也设计了位模式,以便一个加法指令适用于有符号或无符号整数。
有些指令需要知道数据类型。有符号和无符号整数不能用相同的指令进行比较。对于有符号的 32 位int
,位 0xffffffff 表示 -1,小于 0(位 0x00000000),但对于无符号int
位,这些位表示大于零的 4,294,967,295。因此,对于x < y
,如果它们是有符号的,编译器会生成一条指令,如果它们是无符号的,则编译器会生成一条不同的指令。(实际上,对于多种数据类型可能有一个比较指令,但它会产生多个位,指示各种可能的结果,另一条指令根据结果测试这些位和分支。如果比较指令不是针对数据类型定制的,那么测试和分支指令是。)
推荐阅读
- javascript - VueJS - 显示一个带有变量的空 v-html 标签
- python - 如何在 PyTorch 中标准化图像
- unity3d - 使用 Unity HDRP 进行三平面纹理
- android - Kotlin:IT 和 THIS 关键字之间的区别
- php - simple_html_dom: 简单的用例 - 取回存储在 SQLite db 中的数据
- spring-boot - 我们可以在spring boot的GET请求中传递对象吗?
- cyclomatic-complexity - 如果在计算圈复杂度时控制流图包含多个开始和/或停止节点会发生什么
- symfony - api-platform/admin 在安装后抱怨缺少 json 文件
- ckeditor5 - ckeditor5的双向支持
- python - 如何使用 Keras Lambda 层进行切片?