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 位前缀,8dLEA 代码,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.