什么是机器可读代码的语言?

What's machine readable code's language?

基本上,我要问的是计算机理解的语言是什么...... 我看到这个 post 解释了一点 https://www.quora.com/How-are-exe-files-created-And-what-programming-language-are-used-in-creating-them 但它只将其称为 "machine readable code".

我想知道所有编程语言在编译时都转换成什么。 是否可以在不使用编译器的情况下知道 "machine language" 进行编码?

据说它会转换为 "operating system" 或 "execution engine (virtual machine)" 但就是这样吗,我可以拿记事本在那里写下,将其另存为 .exe,它会按照它说的做吗?

如果没有 .exe 就不能创建 .exe 那么你该怎么做?

比如,我可以创建一个独立的 windows 应用程序,而不需要像 Visual Studio/Visual Basic 这样的程序吗?

计算机执行机器代码。这取决于它的CPU。这就是您需要为特殊 CPU-class(例如 i386、SPARC 等)编译软件的原因。因为他们理解不同的机器代码或者他们的构建方式非常不同(例如 RISC 与 CISC)。

在最高级别的程序代码和最低级别的机器代码之间可以有多个层(例如汇编程序、目标代码……)。分层(将复杂性隐藏在下面的层中)是技术中最重要的概念之一。

基本上我们在编译器和解释器之间存在差异。编译器将高级代码(来自人类)翻译成低级代码(例如机器代码)。解释器是一个 运行 程序,它将其输入作为命令。因此它读取代码并按要求执行操作。

通常解释器速度较慢,但​​在平台方面更独立(如果您在多个平台上有解释器程序)。 编译后的程序要快得多,但需要对每个 CPU.

进行特殊处理

EXE 是一种机器代码格式。关于操作系统有几个不同。

我已经提到了汇编程序。它有点高于机器代码,因此对人类来说是可读的。在反汇编中,您获取一个程序(机器代码二进制文件)并将其翻译成汇编程序。 机器代码和汇编程序是一个非常直接的映射。因此,汇编程序中的 1 行将产生 - 可以说 - 机器代码中的 1 到 5 行。 高级语言(例如 C++)中的 1 行将产生更多的机器代码行。 因此,在反汇编过程中,您尝试了解程序并可以使用该信息来满足进一步的需求(例如,解锁代码是如何预期的、破解、...)。

Can I create a stand-alone windows application without any program like Visual Studio/Visual Basic?

理论上是可以的,如果你有时间花(比如几百年),如果你真的想使用十六进制代码,那就太乏味了,即使是汇编程序,这几乎是机器代码之前的最低水平也就是说,比方说,人类友好...... 继续:你不用刀和竹子来建造泰坦尼克号!

首先,linked 引用对于堆栈溢出来说是一件坏事,它可能会消失并毁掉整个问题,使它成为我们必须丢弃的东西。

其次,该参考文献显然是关于 JAVA 和 JVM 的,而且一开始就极具误导性,如果您不了解这些东西,那是一篇非常糟糕的文章。

作为一名程序员,我假设您明白,如果您给 100 个程序员一个编程任务,您最终会得到 1 到 100 个不同的解决方案。

硬件也不例外,给 100 位芯片设计师同样的设计任务,你会得到 1 到 100 种不同的设计。 hardware/board 设计师,同理。如果您告诉芯片设计师发明他们自己的指令集并设计处理器,它将倾向于 100 种不同的设计。如果你给他们指令集(机器代码规范),你仍然会得到 1 到 100 种不同的设计。

如果它是 CISC 或 CISC,你可能最终会使用微编码,使用 RISC 你也可以,但这是 RISC 的想法,而不是 need/want 微编码。

所有编程语言都太模糊了。同时它们通常会转换为一些较低级别的语言,并最终转换为某种parse-able。我们必须含糊其词地回答,因为我可以就此做出的每一个陈述都有例外。但是 C/C++ 是 "compiled",一般来说,是针对特定目标的汇编语言,编译器要么被告知要定位的目标,而通常是你要 运行 编译它的目标,a "cross-compiler" 用于针对不同的目标进行编译。我不想继续使用 generally,mostly 和其他模糊的术语......然后 assembler 将汇编语言主要转换为机器代码,但如果它是 object 那么一些东西就剩下了供 linker 填写并完成。但即使是 .exe 或其他类似的格式(coff、elf 等),文件的大部分也是程序、机器代码和数据,但一些文件告诉操作系统如何加载该程序并启动它。您必须查找每个 "binary" 文件格式类型以了解它们是如何做到这一点的。然后在某些情况下它可能仍然依赖于操作系统。

您绝对没有理由不能直接或在您选择的任何路径中生成这些可执行文件。你可以使用十六进制编辑器(记事本不是其中之一)并开始输入文件的字节,.exe headers,机器代码,数据,整个东西。你当然可以用某种语言编写一个程序编译它 运行 然后那个程序可以直接创建另一个程序,而不是使用编译器只写出字节。

JAVA,早期的 Pascal,Python,BASIC。这些不一定(尽管现在 Pascal 确实如此)直接编译为 "machine code" 用于您 运行 正在使用的处理器。通过设计。 JAVA 和 Python 希望 运行 无处不在,独立于操作系统。他们有自己的机器代码,他们的编译器将源代码编译成机器代码,这不是目标处理器的机器代码,您正在使用的机器代码 运行ning ,而是他们发明的通用机器代码。然后你有一个 JVM JAVA 虚拟机,它是一个程序,可能不是用 JAVA 编写的,它依赖于操作系统并读取 java 机器代码的字节并将其执行为处理器会。 python 和早期的 pascal 一样。 BASIC,传统上你在 运行 时间阅读 BASIC 代码并在你阅读时解析和 运行 它。授予所有这些可能都有一个某人编写的工具链(或者只是 gcc 用于其中一些),而不是编译到语言特定目标,而是可以编译成你正在使用的处理器的机器代码,运行ning,通常和设计不是,但有时可以做到。

处理器本身并没有太大的不同,只是读取机器代码、解析位并执行这些位所说的逻辑。就像 JVM 为 JAVA 做的一样,但在硬件上更快。有时,更可能是 CISC (x86),你有微代码,还有另一个指令集,就像 JVM 一样,它可能在 hardware/logic 的帮助下获取机器代码,并在微代码软件中将其分解并执行它。我们通常看不到那个微码,因为你有 100 个设计师,你会得到 100 个结果,每一代处理器他们都不想携带相同的微码,x86 就是一个很好的例子,尤其是因为英特尔有两个或更多的设计中心做他们自己的事情,每一个或每三个芯片设计都来自这些设计中心之一,所以我们不断地在这些设计中心的偏好之间进行选择。或者至少他们曾经这样做,但现在不知道他们在做什么。

是的,您绝对可以在没有视觉 studio/visual 基础的情况下编写 windows 程序。你可以使用十六进制编辑器,只需输入字节,你可以用汇编语言编写和 assemble 它带有一个 assembler(和 linker 取决于),它不是基于任何视觉的(以 gnu binutils 为例)。

如其他答案和评论中所述,或没有。在这些工具出现之前,"compiling" 和 "assembling" 是一个人写下他们想做的事情(可能是在流程图中),然后用某种形式的汇编语言再次写下来,一些人类的东西可读,然后在旁边或从新页面开始,写下机器代码。然后翻转开关或以其他方式将该机器代码输入处理器并启动它。使用该方法,您最终可以编写一个 assembler,然后现在您有了一个 assembler,您可以在 assembler 中再次编写 assembler 而不是手写机器代码。现在您有了 assembler,您可以发明语言并在 assembler 中实现它们,然后您可以 re-write 使用相同的语言并使用该语言编译它们。并使用该语言来制作其他语言。以及交叉编译语言或 assemble,适用于您发明但没有工具且不想手写机器代码的其他平台。重复几十年,我们就在这里。甚至逻辑都是使用编程语言 verlog and/or vhdl 设计的,这显然受到了 C 和 ADA 等语言的影响,这些语言出现在它们之前。

我拿这个函数,但是函数和程序有什么区别呢?让你思考一下。

unsigned int fun ( unsigned int a, unsigned int b )
{
    return (a+b);
}

我编译了。编译器生成汇编语言作为其输出

    .arch armv5t
    .fpu softvfp
    .eabi_attribute 20, 1
    .eabi_attribute 21, 1
    .eabi_attribute 23, 3
    .eabi_attribute 24, 1
    .eabi_attribute 25, 1
    .eabi_attribute 26, 2
    .eabi_attribute 30, 2
    .eabi_attribute 34, 0
    .eabi_attribute 18, 4
    .arm
    .syntax divided
    .file   "so.c"
    .text
    .align  2
    .global fun
    .type   fun, %function
fun:
    @ args = 0, pretend = 0, frame = 0
    @ frame_needed = 0, uses_anonymous_args = 0
    @ link register save eliminated.
    add r0, r0, r1
    bx  lr
    .size   fun, .-fun
    .ident  "GCC: (Ubuntu 5.2.1-22ubuntu1) 5.2.1 20151010"
    .section    .note.GNU-stack,"",%progbits

然后我assemble那个变成了object。其中的一个 hexdump:

0000000 457f 464c 0101 0001 0000 0000 0000 0000
0000010 0001 0028 0001 0000 0000 0000 0000 0000
0000020 019c 0000 0000 0500 0034 0000 0000 0028
0000030 000a 0007 0001 e080 ff1e e12f 4700 4343
0000040 203a 5528 7562 746e 2075 2e35 2e32 2d31
0000050 3232 6275 6e75 7574 2931 3520 322e 312e
0000060 3220 3130 3135 3130 0030 2941 0000 6100
0000070 6165 6962 0100 001f 0000 3505 0054 0306
0000080 0108 0109 0412 0114 0115 0317 0118 0119
0000090 021a 021e 2e00 7973 746d 6261 2e00 7473
00000a0 7472 6261 2e00 6873 7473 7472 6261 2e00
00000b0 6574 7478 2e00 6164 6174 2e00 7362 0073
00000c0 632e 6d6f 656d 746e 2e00 6f6e 6574 472e
00000d0 554e 732d 6174 6b63 2e00 5241 2e4d 7461
00000e0 7274 6269 7475 7365 0000 0000 0000 0000
00000f0 0000 0000 0000 0000 0000 0000 0001 0000
0000100 0000 0000 0000 0000 0004 fff1 0000 0000
0000110 0000 0000 0000 0000 0003 0001 0000 0000
0000120 0000 0000 0000 0000 0003 0002 0000 0000
0000130 0000 0000 0000 0000 0003 0003 0006 0000
0000140 0000 0000 0000 0000 0000 0001 0000 0000
0000150 0000 0000 0000 0000 0003 0005 0000 0000
0000160 0000 0000 0000 0000 0003 0004 0000 0000
0000170 0000 0000 0000 0000 0003 0006 0009 0000
0000180 0000 0000 0008 0000 0012 0001 7300 2e6f
0000190 0063 6124 6600 6e75 0000 0000 0000 0000
00001a0 0000 0000 0000 0000 0000 0000 0000 0000
*
00001c0 0000 0000 001b 0000 0001 0000 0006 0000
00001d0 0000 0000 0034 0000 0008 0000 0000 0000
00001e0 0000 0000 0004 0000 0000 0000 0021 0000
00001f0 0001 0000 0003 0000 0000 0000 003c 0000
0000200 0000 0000 0000 0000 0000 0000 0001 0000
0000210 0000 0000 0027 0000 0008 0000 0003 0000
0000220 0000 0000 003c 0000 0000 0000 0000 0000
0000230 0000 0000 0001 0000 0000 0000 002c 0000
0000240 0001 0000 0030 0000 0000 0000 003c 0000
0000250 002e 0000 0000 0000 0000 0000 0001 0000
0000260 0001 0000 0035 0000 0001 0000 0000 0000
0000270 0000 0000 006a 0000 0000 0000 0000 0000
0000280 0000 0000 0001 0000 0000 0000 0045 0000
0000290 0003 7000 0000 0000 0000 0000 006a 0000
00002a0 002a 0000 0000 0000 0000 0000 0001 0000
00002b0 0000 0000 0011 0000 0003 0000 0000 0000
00002c0 0000 0000 0094 0000 0055 0000 0000 0000
00002d0 0000 0000 0001 0000 0000 0000 0001 0000
00002e0 0002 0000 0000 0000 0000 0000 00ec 0000
00002f0 00a0 0000 0009 0000 0009 0000 0004 0000
0000300 0010 0000 0009 0000 0003 0000 0000 0000
0000310 0000 0000 018c 0000 000d 0000 0000 0000
0000320 0000 0000 0001 0000 0000 0000          
000032c

对于这个程序来说不一定,但通常更容易看到编译器通过反汇编 object 而不是冗长的汇编产生了什么。

Disassembly of section .text:

00000000 <fun>:
   0:   e0800001    add r0, r0, r1
   4:   e12fff1e    bx  lr

它恰好有我们的机器代码,所以我们可以直接输入这些字节。正如所写的那样,这不是一个完整的程序,因为它至少需要一个特定于操作系统的入口和出口。

我可以 运行 这个处理器上的这个代码我选择了裸机,并且可以用这个 bootstrap:

来包装它
.globl _start
_start:
   mov sp,#0x8000
   bl fun
   b .

assemble 和 link 例如我得到这个

Disassembly of section .text:

00000000 <_start>:
   0:   e3a0d902    mov sp, #32768  ; 0x8000
   4:   eb000000    bl  c <fun>
   8:   eafffffe    b   8 <_start+0x8>

0000000c <fun>:
   c:   e0800001    add r0, r0, r1
  10:   e12fff1e    bx  lr

我可以将其转换为二进制映像,根据处理器和 运行

可以将其加载到 ram 或闪存中
0000000 d902 e3a0 0000 eb00 fffe eaff 0001 e080
0000010 ff1e e12f                              
0000014

不会用basic,不会用visual studio,不会运行宁windows,我可以写这个程序

#include <stdio.h>

static const unsigned int fun[]=
{
0xe3a0d902,
0xeb000000,
0xeafffffe,
0xe0800001,
0xe12fff1e,
};

int main ( void )
{
    FILE *fp;

    fp=fopen("fun.bin","wb");
    if(fp==NULL) return(1);
    fwrite(fun,1,sizeof(fun),fp);
    fclose(fp);
    return(0);
}

编译并 运行 它(是的,来自 exe 的 exe),它会生成与此处 hexdump 中显示的相同的二进制文件:

0000000 d902 e3a0 0000 eb00 fffe eaff 0001 e080
0000010 ff1e e12f                              
0000014

我也可以只使用一个十六进制编辑器,然后只输入这些字节。而不是使用一种语言来创建这个二进制文件。尽管它仍然是一个 exe 的 exe,因为我使用了一个程序 hexeditor。我在这里粗略地说 exe,因为它不是 .exe 文件格式,而是 exe,因为它是一个可执行程序,尽管几乎没有用。

是的,我很清楚在调用 fun 之前我没有加载 r0 或 r1,处理器寄存器中的位唤醒无关紧要(除了一些硅模拟,它们不是两个状态,而是三个、四个或更多状态并取决于逻辑设计)所以添加将起作用。