- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
汇编、机器码、字节码和操作码之间的实际关系是什么?
我已经阅读了大部分关于汇编和机器代码的 SO 问题,例如 this ,但它们太高级了,没有显示实际汇编代码转换为机器代码的示例。结果,我仍然不明白它在更深层次上是如何工作的。
这个问题的理想答案将显示一些汇编代码的特定示例,例如下面的片段,以及每个汇编指令如何映射到机器代码、字节码和/或操作码。像这样的答案对以后学习汇编的人会很有帮助,因为这几天的挖坑我还没有找到明确的总结。
我正在寻找的主要内容是:
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
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.
13 82 6a
每个单独地称为“操作码”,并且它们的整个集合称为“字节码”作为一个包罗万象的术语。此外,我找不到列出所有这些 2 位十六进制数字的表格,以及它们与机器代码或程序集的关系。
最佳答案
是的,每个架构都有一个指令集引用,给出了指令是如何编码的。对于 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
B804000002 mov rax, 0x2000004
.那里
B8
是操作码,
04000002
是立即数。
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
进入
0
和
5
并在表中查找
A-3
在第 0 行,第 5 列。我们发现它是一个
syscall
操作说明。
关于c - 汇编、机器码、字节码和操作码之间的实际关系是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27629390/
我试图在图形模式下打印一个字符。通常当我打印我正在做的一个字符时: mov ah,14 ; ah=14 mov al,'x' int 10h ; print the character 这
我试图通过更改其中的一个字节来修改存储在内存中的字符串。我为此使用了 movb,但由于某种原因,给定内存位置的字节没有改变。 在 gdb 调试器上: 14 movb %al, (%r10) # nex
我一直在阅读一些汇编代码,并且开始发现调用指令实际上是与程序计数器相关的。 但是,每当我使用 Visual Studio 或 Windbg 进行调试时,它总是显示 call 0xFFFFFF ...这
我最近一直在使用 Visual C++ 中的内联汇编,我想知道是否可以直接向堆栈上的局部变量添加值,例如: push 5 add [esp], 7 这样做可以吗?我问这个问题是因为我在执行此操作时随机
我有下一个代码: mov al, -5 add al, 132 add al, 1 据我检查,溢出标志和进位标志将在第一个操作中设置,而在第二个操作中,仅设置溢出。 但我不明白为什么: 在无符号数中,
在 64 位 x86 汇编 nasm 中,如何将单个字节从寄存器移动到 .data 节中定义的内存位置? 我知道这有效 global _main section .data quotient db 0
我的汇编代码有问题。我想打印存储在寄存器 cx 中的数字,但是当我尝试打印它时,它打印的是 ascii 字符而不是 ascii 数字,所以我决定编写一个程序将 ascii char 转换为 ascii
为什么第 1B 行的跳转指令(例如)变成了 EBBD? 我知道“jmp”= EB但是BD是怎么计算的呢? 最佳答案 短跳转使用一个带符号的偏移量添加到 JMP 之后的指令地址。 例如,第一个 JMP
以下两者有什么区别: mov eax, [eax+4] 和 add eax, 4 mov eax, [eax] 如果不是,那么汇编器是否会选择哪个来进行某种优化? 最佳答案 这
看《The Shellcoder's Handbook》中的一些汇编和反汇编代码,发现一条指令的序列操作数是不一样的。 例如,在 assembly 上: mov ebx,0 并且,在反汇编时: mov
我有这个非常简单的汇编代码: start: add ax, 100 ; if ax overflow add to bx 1 jmp start 但我不知道如何检测 ax 寄存器溢出,有人可以帮
在 64 位 x86 汇编 nasm 中,如何将单个字节从寄存器移动到 .data 节中定义的内存位置? 我知道这有效 global _main section .data quotient db 0
我的汇编代码有问题。我想打印存储在寄存器 cx 中的数字,但是当我尝试打印它时,它打印的是 ascii 字符而不是 ascii 数字,所以我决定编写一个程序将 ascii char 转换为 ascii
我正在学习一些关于操作系统开发的教程,我发现了一篇关于多重引导 header 。这些是您必须定义的一些“神奇”值才能使用GRUB2。这些是命令: # Declare constants used f
为什么第 1B 行的跳转指令(例如)变成了 EBBD? 我知道“jmp”= EB但是BD是怎么计算的呢? 最佳答案 短跳转使用一个带符号的偏移量添加到 JMP 之后的指令地址。 例如,第一个 JMP
我正在尝试从内存中复制一些单词并使用汇编将其保存到另一个内存地址。我正在尝试为其编写代码,但我不确定其中的某些部分。我将简要描述我想要做什么。 源地址、目标地址和要复制的字数是函数的输入参数。 最佳答
当我们想要像这样创建一个初始化变量时: name db 'zara ali' 我们创建了一个字节大小变量,但我们在其中存储了一个字符串 这怎么可能?? 当我们使用这条指令时: MOV ecx, nam
我还是汇编的新手,我还不知道汇编中的许多命令代码。我想在 16 位寄存器中进行除法。我想打印它的内容。我知道我需要将寄存器的内容转换为 ASCII 进行打印,但同样,我的问题是除法。请帮我。 比如cx
使用有什么区别: c.eq.s $1, $2 bc1t L2 并使用: beq $1, $2, L2 如果他们做同样的事情,为什么有两种分支方式?如果它们不同,那么它们各自的好处是什么
源代码: int main() { int i; for(i=0, i : push rbp 2. 0x000055555555463b :
我是一名优秀的程序员,十分优秀!