LEA 指令操作码生成
LEA instruction opcode generation
这个问题不是关于 LEA 指令的问题,根本不是关于它是如何工作的,它不是重复的。这是关于此指令的 OPCODE 生成。
LEA 操作码中的操作数是多少?
这是我的 "hello world.fasm":
汇编程序:
format ELF64 executable at 0000000100000000h ; put image over 32-bit limit
segment readable executable
entry $
mov edx,msg_size ; CPU zero extends 32-bit operation to 64-bit
; we can use less bytes than in case mov rdx,...
lea rsi,[msg]
mov edi,1 ; STDOUT
mov eax,1 ; sys_write
syscall
xor edi,edi ; exit code 0
mov eax,60 ; sys_exit
syscall
segment readable writeable
msg db 'Hello 64-bit world!',0xA
msg_size = $-msg
十六进制转储:
000000b0 ba 14 00 00 00 48 8d 35 15 10 00 00 bf 01 00 00 |.....H.5........|
000000c0 00 b8 01 00 00 00 0f 05 31 ff b8 3c 00 00 00 0f |........1..<....|
000000d0 05 48 65 6c 6c 6f 20 36 34 2d 62 69 74 20 77 6f |.Hello 64-bit wo|
000000e0 72 6c 64 21 0a |rld!.|
000000e5
如您所见,感兴趣的指令 lea rsi, [msg]
具有操作码:48 8d 35 15 10 00 00
。从 CPU 指令参考我可以看出 48
是排序的 64 位前缀,8d
是 LEA
代码,35
是目标寄存器 rsi
引用,而 15 10 00 00
是...???这是什么?
0x15
是十进制的 21
,我可以用手指跟踪十六进制转储来计算 "Hello world" 消息正好在 LEA rsi, [msg]
指令之后的 21 个字节。所以肯定是相对地址,但是10 00 00
是从哪里来的呢?如果是 15
00 00 00
我会理解,但由于某种原因它是 15
01 00 00
.
不幸的是 CPU 推荐信不是很有用,它们太正式了,我无法接受它们。它们看起来像这样:
8D r LEA Gvqp M gen datamov Load Effective Address
所以请解释一下 LEA
操作码在这种情况下是如何生成的,如果可能的话,一般情况下。
我将回答您关于 15 10 00 00
是什么的问题,而不是关于 LEA
通常如何编码的其他问题。
让我们通过 readelf
获取有关可执行文件的一些信息:
$ readelf -l leatest
Program headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x00000000000000b0 0x00000001000000b0 0x00000001000000b0 0x0000000000000021 0x0000000000000021 R E 1000
LOAD 0x00000000000000d1 0x00000001000010d1 0x00000001000010d1 0x0000000000000014 0x0000000000000014 RW 1000
然后让我们用ndisasm
(来自NASM)反汇编二进制文件:
ndisasm -b 64 leatest
000000B0 BA14000000 mov edx,0x14
000000B5 488D3515100000 lea rsi,[rel 0x10d1]
000000BC BF01000000 mov edi,0x1
000000C1 B801000000 mov eax,0x1
000000C6 0F05 loadall286
000000C8 31FF xor edi,edi
000000CA B83C000000 mov eax,0x3c
000000CF 0F05 loadall286
000000D1 48 rex.w ; <-- The string starts here
000000D2 656C gs insb
000000D4 6C insb
000000D5 6F outsd
000000D6 2036 and [rsi],dh
000000D8 342D xor al,0x2d
000000DA 62 db 0x62
000000DB 697420776F726C64 imul esi,[rax+0x77],dword 0x646c726f
000000E3 210A and [rdx],ecx
因此,您的第二个段(字符串所在的位置)的虚拟地址为 0x00000001000010d1
,而代码从虚拟地址 0x00000001000000b0
开始。这些段在 4096 字节边界 (0x1000) 上对齐,因此字符串位于 0x10D1 - 0xBC
相对于使用的指令,等于 0x1015
。因此,您在 hexdump 中看到 15 10 00 00
的原因是,这是相对偏移量 0x00001015
.
这个问题不是关于 LEA 指令的问题,根本不是关于它是如何工作的,它不是重复的。这是关于此指令的 OPCODE 生成。
LEA 操作码中的操作数是多少?
这是我的 "hello world.fasm":
汇编程序:
format ELF64 executable at 0000000100000000h ; put image over 32-bit limit
segment readable executable
entry $
mov edx,msg_size ; CPU zero extends 32-bit operation to 64-bit
; we can use less bytes than in case mov rdx,...
lea rsi,[msg]
mov edi,1 ; STDOUT
mov eax,1 ; sys_write
syscall
xor edi,edi ; exit code 0
mov eax,60 ; sys_exit
syscall
segment readable writeable
msg db 'Hello 64-bit world!',0xA
msg_size = $-msg
十六进制转储:
000000b0 ba 14 00 00 00 48 8d 35 15 10 00 00 bf 01 00 00 |.....H.5........|
000000c0 00 b8 01 00 00 00 0f 05 31 ff b8 3c 00 00 00 0f |........1..<....|
000000d0 05 48 65 6c 6c 6f 20 36 34 2d 62 69 74 20 77 6f |.Hello 64-bit wo|
000000e0 72 6c 64 21 0a |rld!.|
000000e5
如您所见,感兴趣的指令 lea rsi, [msg]
具有操作码:48 8d 35 15 10 00 00
。从 CPU 指令参考我可以看出 48
是排序的 64 位前缀,8d
是 LEA
代码,35
是目标寄存器 rsi
引用,而 15 10 00 00
是...???这是什么?
0x15
是十进制的 21
,我可以用手指跟踪十六进制转储来计算 "Hello world" 消息正好在 LEA rsi, [msg]
指令之后的 21 个字节。所以肯定是相对地址,但是10 00 00
是从哪里来的呢?如果是 15
00 00 00
我会理解,但由于某种原因它是 15
01 00 00
.
不幸的是 CPU 推荐信不是很有用,它们太正式了,我无法接受它们。它们看起来像这样:
8D r LEA Gvqp M gen datamov Load Effective Address
所以请解释一下 LEA
操作码在这种情况下是如何生成的,如果可能的话,一般情况下。
我将回答您关于 15 10 00 00
是什么的问题,而不是关于 LEA
通常如何编码的其他问题。
让我们通过 readelf
获取有关可执行文件的一些信息:
$ readelf -l leatest Program headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x00000000000000b0 0x00000001000000b0 0x00000001000000b0 0x0000000000000021 0x0000000000000021 R E 1000 LOAD 0x00000000000000d1 0x00000001000010d1 0x00000001000010d1 0x0000000000000014 0x0000000000000014 RW 1000
然后让我们用ndisasm
(来自NASM)反汇编二进制文件:
ndisasm -b 64 leatest
000000B0 BA14000000 mov edx,0x14
000000B5 488D3515100000 lea rsi,[rel 0x10d1]
000000BC BF01000000 mov edi,0x1
000000C1 B801000000 mov eax,0x1
000000C6 0F05 loadall286
000000C8 31FF xor edi,edi
000000CA B83C000000 mov eax,0x3c
000000CF 0F05 loadall286
000000D1 48 rex.w ; <-- The string starts here
000000D2 656C gs insb
000000D4 6C insb
000000D5 6F outsd
000000D6 2036 and [rsi],dh
000000D8 342D xor al,0x2d
000000DA 62 db 0x62
000000DB 697420776F726C64 imul esi,[rax+0x77],dword 0x646c726f
000000E3 210A and [rdx],ecx
因此,您的第二个段(字符串所在的位置)的虚拟地址为 0x00000001000010d1
,而代码从虚拟地址 0x00000001000000b0
开始。这些段在 4096 字节边界 (0x1000) 上对齐,因此字符串位于 0x10D1 - 0xBC
相对于使用的指令,等于 0x1015
。因此,您在 hexdump 中看到 15 10 00 00
的原因是,这是相对偏移量 0x00001015
.