1
Lqxc 2022-12-03 21:39:37 +08:00 via Android
跟编译器没啥关系,跟组成原理有关系。如果你说的是 cpu 如何知道哪些是指令,哪些是数据,这个是指令集定义的。而且计算机不知道你的是数据还是机器码,elf 就可以被 linux os 加载并执行,而同时也能被当作数据文件读取。
|
2
lance6716 2022-12-03 21:44:26 +08:00 via Android
数字就是指令,指令就是数字。记得是叫冯诺依曼结构?
|
3
cpstar 2022-12-03 21:55:44 +08:00
编译出来的东西,会按照操作系统相应的可执行文件结构进行内容划分,包括数据段、代码段等。然后代码段就是各种指令,如果放错乱了,结果就是把数据当指令进行操作,那就是乱七八糟直到程序崩溃(当然也可能把操作系统弄崩溃)。
to 1#,其实还是编译器(准确讲叫连接器)的工作,搞成操作系统对应的文件结构,然后操作系统加载并创建进程执行相应内容。跟组成原理关系不大。 |
4
GuuJiang 2022-12-03 21:56:01 +08:00 via iPhone
不知道你有没有遇到过在 Windows 系统上弹出一个错误提示,内容为“非法指令”
你这个问题要分几个层次来回答 1. 计算机怎么区分机器码和其它内容 每种架构的 CPU 有个东西叫做指令集,规定了哪些是合法的指令,CPU 总是无条件地把程序寄存器指向的内容当成指令(哪怕由于堆栈破坏等原因导致程序寄存器指向了数据段或者其它无效内容),尽量地去尝试译码,如果确实碰到了无法译码的内容则产生中断 2. 上面是从单条指令的角度来说,但是我猜你可能误认为 CPU 是直接执行编译输出的文件,所以会有这个疑问,实际上编译生成的可执行文件要遵循目标操作系统上的可执行文件的特定结构,例如 PE 、elf 等,而操作系统在加载可执行文件时首先依据文件结构找到其中的代码段,然后才是交给 CPU 执行 |
5
Jooooooooo 2022-12-03 22:09:03 +08:00
按照位置来的
比如有个起始符 START 识别完这个之后, 后面紧跟就是一个 指令+数据, 然后如此反复 有一种攻击方法, 就是错乱这个识别, 让机器把数据识别成指令, 就可以执行任意想执行的东西了 你可以研究下 JAVA 代码编译成的 .class 文件机器是怎么读取的就明白了 |
6
ww2000e 2022-12-03 22:35:44 +08:00
如果是汇编器,那是按照 cpu 硬件定好的规矩生成的二进制,如果是高级语言的,还要过一道操作系统,二进制按操作系统要求格式生成的,二进制本身依然还是按 cpu 硬件要求生成
|
7
GeruzoniAnsasu 2022-12-03 22:44:30 +08:00
|
8
Coelacanth 2022-12-03 23:12:06 +08:00
|
9
Reficul 2022-12-04 04:19:55 +08:00 via iPhone
elf 和 pe 格式
|
10
FlossStunning 2022-12-04 15:56:21 +08:00
一般来说, 当编译器将源代码编译为机器码时, 它会在机器码文件的开头添加一个特殊的头部, 该头部包含了关于该文件的一些信息, 其中包括文件类型。当计算机加载机器码文件时, 它会检查文件的头部信息, 如果发现该文件的类型是机器码, 它就会将其加载到内存中并执行。
——ChatGPT |
11
Cola98 2022-12-05 15:56:53 +08:00
因为这些都是 CPU 提供的指令,准确来说是 CPU 体系提供的
|
12
agagega 2022-12-05 17:02:47 +08:00
当你运行一个程序的时候,操作系统会读取这个程序的内容到内存,解析它的结构,并告诉 CPU 「从这个地方开始执行」。也就是说,CPU 并不会去尝试「区分」一块内存是指令还是数据(也没办法区分),只是从某个地方开始,一条一条地执行下去,遇到跳转指令再改变当前读取指令的位置(即所谓的 Program Counter 寄存器)。所有从某个位置读数据的操作,都是指令告诉 CPU 去读的。
|
13
liamhuangzzzz 2022-12-06 17:41:52 +08:00
@GeruzoniAnsasu 这两天啃完了前两章,受益匪浅,谢谢老哥,我在考虑要不要把后面的都啃完。
|