我只是想知道,我们可以在没有操作系统的机器上执行程序吗?
此外,我听说Linux内核是用C语言编写的,内核是在启动过程中运行的,所以我只是想知道计算机如何在没有编译的情况下理解该语言?
为什么如果你在十六进制编辑器中打开一个EXE,你会看到各种各样的东西.如果计算机只能理解二进制文件,那么文件中只能看到2个可能的符号吗?谢谢
关于什么机器代码实际上似乎有很多意见.我听说有人说它是汇编,二进制或十六进制.
说机器代码本质上是特定处理器的一组指令是否正确?如果是这样,我想这些可以用二进制或十六进制表示法或汇编表示.但是非翻译的"实际"机器代码是什么样的?它是基于架构的字大小?或者是十六进制的所有意图和目的的默认表示?
坐在硬盘上的样子是什么样的?坐在登记册上看起来像什么?处理它的时候,它只是一组电压变化吗?
这是我之前的问题的后续跟进.我不相信Lisp代码与Von Neumann架构上的机器代码一样是Homoiconic.对我来说似乎很明显,在这两种情况下代码都表示为数据,但似乎很明显,你可以在机器代码中比在Lisp中更自由地利用这个属性.
在使用机器代码时,自我修改代码非常容易,它总是偶然发生,通常是偶然的,并且(根据我的经验)是搞笑的结果.在编写一个简单的"打印数字0-15"程序时,我的一个指针可能会出现"off by one"错误.我最终会意外地将寄存器1中的任何内容转储到包含下一条指令的内存中的地址中,而是执行随机指令.(当它是某种"goto"时总是很棒.上帝知道它会在哪里结束以及在那之后会发生什么)
代码和数据之间确实没有分离.一切都是一条指令(即使它只是一个NOP),一个指针和一个普通的旧数字.并且代码可能会在您眼前改变.
请帮我搞一个Lisp场景我一直在摸不着头脑.说我有以下程序:
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
; -- Demonstrate the output of factorial --
; -- The part that does the Self modifying goes here –
; -- Demonstrate the changed output of factorial
Run Code Online (Sandbox Code Playgroud)
现在我想要发生的是在这个程序中添加一些Lisp代码,它会将*更改为+,将<=更改为a> =,在那里的某处粘贴一个(+ 1 2 3),并且通常会对函数进行操作起来.然后我希望程序执行结果的绝对混乱.
关键点:除非我在示例代码中犯了一些致命错误,否则您只能更改该-– More code goes here –-部分.你在上面看到的是代码.我不希望你引用整个列表并将其存储在变量中,以便可以将其作为具有相同名称的单独函数进行操作和吐出; 我不希望将阶乘的标准重新定义视为完全不同的东西.我想要那些代码,就在那里,我可以在屏幕上看到我在眼前改变自己,就像机器代码一样.
如果这是一个不可能/不合理的请求,那么它只会在我的脑海中进一步巩固Homoiconicity不是语言有或没有的离散属性的想法,它是一个谱,而Lisp并不处于最前沿.(或者Lisp就像他们来的同性恋,我正在寻找一些其他术语来描述机器代码式的自我修改)
该Intel® 64 and IA-32 Software Developer's Manual, Volume 2A, Section 3.1.1.1提到的符号ct来表示操作码之后的10字节值.然而,我无法找到任何用它注释的指令.我错过了什么或没有指令采用10字节的立即值?
只是想知道.NET应用程序是否可以提前编译为本机代码?即使我可以,我也不打算这样做; 我只是好奇.
谢谢
我有一小段(x86)程序集,我试图找出它的作用.
...
6: 81 ec 00 01 00 00 sub $0x100, %esp
c: 31 c9 xor %ecx , %ecx
e: 88 0c 0c mov %cl , (%esp, %ecx, 1)
11: fe c1 inc %cl
13: 75 f9 jne 0xe
....
Run Code Online (Sandbox Code Playgroud)
它看起来像循环,直到"JNE"评估为false,即零标志= 0.(可能是它将数字1,2,3 ......放入堆栈?)
从我对程序集的简短调查(我刚接触到它)接缝你通过做一个比较操作(CMP)设置零标志,但我没有看到比较操作.
那么,它会在什么条件下突破这个循环呢?
我正在阅读:https : //www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf 我在第 8 页阅读了以下内容:
e9 fd ff 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa
最初的三个字节,十六进制为 0xe9、0xfd 和 0xff,实际上是 CPU 制造商定义的机器代码指令,用于执行无限跳转。
他们所说的“执行无休止的跳跃”是什么意思?
std::launder故意混淆抽象机/编译器的指针的来源,以便源和结果可能具有不同的生命周期和类型。当用于例如(静态)向量情况时,您有一个半大的存储空间来保存多个对象,清洗指向切片的“干”指针会产生适当类型的干净但“湿”的指针(湿的,如清洗过的) :
// appropriately sized and aligned data member
std::byte* const dry = data + some_index;
T* const wet = std::launder(reinterpret_cast<T*>(dry));
Run Code Online (Sandbox Code Playgroud)
这个想法是编译器无法“看到”过去的std::launder. 即使没有实现位于单独的编译单元中。问题是这是否仍然会浪费合理的优化机会。
例如:
T object;
// ...
T* ptr = &object;
ptr->member = 42;
return ptr->member;
Run Code Online (Sandbox Code Playgroud)
据推测,在读取其内容时,不需要单独检索object和的地址,因为它可能仍然位于某个寄存器中。member但是,如果对访问的访问ptr总是被洗白,例如,如果它是从operator[](size_type)必须洗白存储指针的某些地方检索的,则这可能不再成立:
storage[i].member = 42;
return storage[i].member;
// storage[]() launders
Run Code Online (Sandbox Code Playgroud)
storage[i]?std::launder一个除了神奇地使 UB 代码变得非 UB 之外什么都不做的函数?含义:如果这是正确的,则意味着类向量结构(即当您需要最高性能时使用的结构)将因引入std::launder. std::vector<T>就会落后于简单的T*。
尽管单词的常见定义(如维基百科所述)是:
用于指定存储器中的位置的最大可能地址大小通常是硬件字(这里,“硬件字”是指处理器的全尺寸自然字,而不是使用的任何其他定义)。
根据一些消息来源,x86 系统注意到它被视为 16 位:
在 x86 PC(Intel、AMD 等)中,虽然架构很早就支持 32 位和 64 位寄存器,但其本机字大小可以追溯到 16 位起源,“单个”字为 16 位。“双”字是 32 位。请参阅 32 位计算机和 64 位计算机。
然而英特尔的官方文档(sdm 第 2 卷,第 1.3.1 节)指出:
这意味着字的字节从最低有效字节开始编号。图 1-1 说明了这些约定。
图 1-1 显示了 x86-64 上下文中单词的小端序列中的 4 个字节,而不是 2 个字节或 8 个字节(如上面链接的来源的不同定义所建议的那样):
我对这一切真正感到困惑的是如何获取和解析指令。我正在编写一个模拟器,一旦我解析 PE 格式的可执行文件并进入文本部分,如果我要遵循 4 字节小端格式,这是否意味着将首先解析第 4 个字节?
让我们组成一些字节,例如:
.text segment buffer:
< 0x10, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 > ....
Run Code Online (Sandbox Code Playgroud)
我会将第一条指令解析为 1C、1B、1A、10、20、1F、1E、1D ...(等等,由于长度可变,显然可能有更多的单词需要读取,具体取决于这里的实际字节是什么)?
machine-code ×10
assembly ×3
c++ ×2
x86 ×2
x86-64 ×2
.net ×1
binary ×1
boot ×1
c ×1
compilation ×1
cpu ×1
cpu-word ×1
endianness ×1
executable ×1
hex ×1
intel ×1
linux-kernel ×1
lisp ×1
native ×1
optimization ×1
sector ×1
stdlaunder ×1