gpt4 book ai didi

c - 汇编、机器码、字节码和操作码之间的实际关系是什么?

转载 作者:太空狗 更新时间:2023-10-29 16:45:40 29 4
gpt4 key购买 nike

汇编、机器码、字节码和操作码之间的实际关系是什么?

我已经阅读了大部分关于汇编和机器代码的 SO 问题,例如 this ,但它们太高级了,没有显示实际汇编代码转换为机器代码的示例。结果,我仍然不明白它在更深层次上是如何工作的。

这个问题的理想答案将显示一些汇编代码的特定示例,例如下面的片段,以及每个汇编指令如何映射到机器代码、字节码和/或操作码。像这样的答案对以后学习汇编的人会很有帮助,因为这几天的挖坑我还没有找到明确的总结。

我正在寻找的主要内容是:

  • 汇编代码片段
  • 一段机器代码
  • 汇编片段和机器代码之间的映射 (如何进行映射,或至少是一些一般示例,以及您如何知道如何进行此操作,网络上的所有信息在哪里)
  • 如何解释机器码 (比如操作码是否有某种关联,以及网络上关于所有这些数字的含义的所有信息在哪里)

  • 注意:我没有计算机科学背景,所以在过去的几年里我只是慢慢地降低了水平,现在已经达到了想要理解汇编和机器代码的地步。

    汇编和机器码的关系

    我目前的理解是“汇编器”(例如 NASM)采用汇编代码并从中创建机器代码。

    所以当你编译一些像这样的程序集时 example.asm :
    global main
    section .text

    main:
    call write

    write:
    mov rax, 0x2000004
    mov rdi, 1
    mov rsi, message
    mov rdx, length
    syscall

    section .data
    message: db 'Hello, world!', 0xa
    length: equ $ - message

    (用 nasm -f macho64 -o example.o example.asm 编译它)。它输出这个 example.o目标文件:
    cffa edfe 0700 0001 0300 0000 0100 0000
    0200 0000 0001 0000 0000 0000 0000 0000
    1900 0000 e800 0000 0000 0000 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    2e00 0000 0000 0000 2001 0000 0000 0000
    2e00 0000 0000 0000 0700 0000 0700 0000
    0200 0000 0000 0000 5f5f 7465 7874 0000
    0000 0000 0000 0000 5f5f 5445 5854 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    2000 0000 0000 0000 2001 0000 0000 0000
    5001 0000 0100 0000 0005 0080 0000 0000
    0000 0000 0000 0000 5f5f 6461 7461 0000
    0000 0000 0000 0000 5f5f 4441 5441 0000
    0000 0000 0000 0000 2000 0000 0000 0000
    0e00 0000 0000 0000 4001 0000 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    0000 0000 0000 0000 0200 0000 1800 0000
    5801 0000 0400 0000 9801 0000 1c00 0000
    e800 0000 00b8 0400 0002 bf01 0000 0048
    be00 0000 0000 0000 00ba 0e00 0000 0f05
    4865 6c6c 6f2c 2077 6f72 6c64 210a 0000
    1100 0000 0100 000e 0700 0000 0e01 0000
    0500 0000 0000 0000 0d00 0000 0e02 0000
    2000 0000 0000 0000 1500 0000 0200 0000
    0e00 0000 0000 0000 0100 0000 0f01 0000
    0000 0000 0000 0000 0073 7461 7274 0077
    7269 7465 006d 6573 7361 6765 006c 656e
    6774 6800

    (即 example.o 的全部内容)。当你然后“链接”使用 ld -o example example.o ,它给你更多的机器代码:
    cffa edfe 0700 0001 0300 0080 0200 0000
    0d00 0000 7803 0000 8500 0000 0000 0000
    1900 0000 4800 0000 5f5f 5041 4745 5a45
    524f 0000 0000 0000 0000 0000 0000 0000
    0010 0000 0000 0000 0000 0000 0000 0000
    0000 0000 0000 0000 0000 0000 0000 0000
    0000 0000 0000 0000 1900 0000 9800 0000
    5f5f 5445 5854 0000 0000 0000 0000 0000
    0010 0000 0000 0000 0010 0000 0000 0000
    ... 523 lines of this

    但是它是如何从组装说明到这些数字的呢?是否有某种标准引用列出了所有这些数字,以及它们对于您使用的任何架构的含义(我在 OSX 上通过 NASM 使用 x86-64),以及每组数字如何映射到每个汇编指令?

    我知道每台机器的机器代码都不同,并且有几十种甚至数百种不同类型的机器。所以我目前不是在寻找如何将程序集转换为每个程序(那会很复杂)。我只是对一个说明转换如何工作的示例感兴趣,任何架构都可以作为示例。从那时起,我可以去研究我感兴趣的特定架构并找到映射。

    汇编和字节码之间的关系(或称为“操作码”?)

    所以从我到目前为止的阅读来看,汇编被转换为机器代码,如上所示。

    但现在我很困惑。我看到人们谈论字节码,例如 in this SO answer ,显示如下内容:

    void myfunc(int a) {
    printf("%s", a);
    }

    The assembly for this function would look like this:

    OP Params OpName     Description
    13 82 6a PushString 82 means string, 6a is the address of "%s"
    So this function pushes a pointer to "%s" on the stack.
    13 83 00 PushInt 83 means integer, 00 means the one on the top of the stack.
    So this function gets the integer at the top of the stack,
    And pushes it on the stack again
    17 13 88 Call 1388 is printf, so this calls the printf function
    03 02 Pop This pops the two things we pushed back off the stack
    02 Return This returns to the calling code.


    那么我就糊涂了。做一些挖掘,我不知道这些 2 位十六进制数字中的每一个是否像 13 82 6a每个单独地称为“操作码”,并且它们的整个集合称为“字节码”作为一个包罗万象的术语。此外,我找不到列出所有这些 2 位十六进制数字的表格,以及它们与机器代码或程序集的关系。

    总而言之,我非常期待一个示例,展示汇编指令如何映射到机器代码,以及它与字节码和/或操作码的关系。 (我不是在寻找编译器如何执行此操作,而是在寻找一般映射的工作原理)。我认为这不仅可以为我自己,也可以为以后有兴趣了解更多有关裸机的许多人澄清这一点。

    了解这一点很有值(value)的另一个原因是,人们可以了解 LLVM 编译器如何生成机器代码。他们是否有某种 2 位操作码或机器码 4 位序列的“完整列表”,并且确切地知道它们如何映射到任何特定于架构的程序集?他们从哪里得到这些信息?对这个整体问题的回答将使 LLVM 如何实现其代码生成更加清晰。

    更新

    从@HansPassant 的评论更新。我实际上不在乎这些词之间的实际区别是什么,抱歉,如果不清楚。我只想知道这一点:汇编如何映射到机器代码(以及从哪里开始寻找在网络上保存该信息的引用),以及在该过程中的任何地方都使用了操作码或字节码?如果是这样怎么办?

    最佳答案

    是的,每个架构都有一个指令集引用,给出了指令是如何编码的。对于 x86,它是 Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z

    大多数汇编程序,包括 nasm , 可以为您生成一个列表文件。将您的示例代码提供给 nasm -l ,我们得到:

     1                                  global main
    2 section .text
    3
    4 main:
    5 00000000 E800000000 call write
    6
    7 write:
    8 00000005 B804000002 mov rax, 0x2000004
    9 0000000A BF01000000 mov rdi, 1
    10 0000000F 48BE- mov rsi, message
    11 00000011 [0000000000000000]
    12 00000019 BA0E000000 mov rdx, length
    13 0000001E 0F05 syscall
    14
    15 section .data
    16 00000000 48656C6C6F2C20776F- message: db 'Hello, world!', 0xa
    17 00000009 726C64210A
    18 length: equ $ - message

    您可以在第三列中看到生成的机器码(第一列是行号,第二列是地址)。

    请注意,汇编器的输出是一个目标文件,而链接器的输出是一个可执行文件。这两者都具有复杂的结构,并且不仅仅包含机器代码。这就是为什么您的 hexdump 与上述 list 不同的原因。

    操作码通常被认为是指定要执行的操作的机器代码指令的一部分。例如,在上面的代码中,您有 B804000002 mov rax, 0x2000004 .那里 B8是操作码, 04000002是立即数。

    字节码通常不在程序集上下文中使用,它可以被认为是虚拟机的机器代码。

    对于演练,x86 是一个非常复杂的架构。但是你的示例代码恰好有一个简单的指令, syscall .那么让我们看看如何将其转换为机器代码。打开上面提到的引用pdf,然后转到关于 syscall的部分在第 4 章中。您将立即看到它列为操作码 0F 05 .由于它不需要任何操作数,我们就完成了,那 2 个字节是机器码。我们如何把它转回来?转至 Appendix A: Opcode map .栏目 A.1告诉我们: For 2-byte opcodes beginning with 0FH (Table A-3), skip any instruction prefixes, the 0FH byte (0FH may be preceded by 66H, F2H, or F3H) and use the upper and lower 4-bit values of the next opcode byte to index table rows and columns. .好的,所以我们跳过 0F并拆分 05进入 05并在表中查找 A-3在第 0 行,第 5 列。我们发现它是一个 syscall操作说明。

    关于c - 汇编、机器码、字节码和操作码之间的实际关系是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27629390/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com