9. 指令解析
来源:互联网 发布:vr头显 知乎 定位 编辑:程序博客网 时间:2024/06/06 02:03
9. 指令解析
上一页 返回目录 下一页
一、 assemble
这里我想写一段汇编代码,作为源代码,然后手工译为机器编码
1、 assembly 源代码
这段是摘自我的 mouseOS 里面的一段代码 kstrcmp() 用来比较这个字符串是否相等:
;-------------------------------------------------------
; long kstrcmp(const char *s1, const char *s2);
; input: rdi: s1 rsi: s2
; return value: 1: equal 0: not equal
;-------------------------------------------------------
__kstrcmp:
xor rax, rax
kstrcmp_loop:
movzx r10, byte [rdi]
movzx r11, byte [rsi]
cmp r10, r11
jnz kstrcmp_done
test r10, r10
jz kstrcmp_eql
inc rdi
inc rsi
jmp kstrcmp_loop
kstrcmp_eql:
inc rax
kstrcmp_done:
ret
2、 encodes (机器编码)
下面是我完全用人工译出来的机器码:
0: 48 31 c03: 4c 0f b6 17
7: 4c 0f b6 1e
b: 4d 39 da
e: 75 10 * (jnz kstrcmp_done)
10: 4d 85 d2
13: 74 08 * (jz kstrcmp_eql)
15: 48 ff c7
18: 48 ff c6
1b: eb e6 * (jmp kstrcmp_loop)
1d: 48 ff c0
20: c3
下面再看一看 nasm 编译的情况:
00000000 4831C0 xor rax,rax00000003 4C0FB617 movzx r10,byte [rdi]
00000007 4C0FB61E movzx r11,byte [rsi]
0000000B 4D39DA cmp r10,r11
0000000E 7513 jnz 0x23 * (jnz kstrcmp_done)
00000010 4D85D2 test r10,r10
00000013 740B jz 0x20 * (jz kstrcmp_eql)
00000015 48FFC7 inc rdi
00000018 48FFC6 inc rsi
0000001B E9E3FFFFFF jmp dword 0x3 * (jmp kstrcmp_loop)
00000020 48FFC0 inc rax
00000023 C3 ret
对比 nasm 编译出来的机器码,不难发现 nasm 并不能编译出最优秀的代码:
(1)nasm 译出 0x23 个 bytes,比我手工译出来的要多 3 个 bytes。
(2)nasm 对于指令 jmp kstrcmp_loop 译为 5 bytes,而实际上只需要译为 2 bytes 就行了。
这是因为 nasm 使用了 32 位的 immediate 值,而我使用了 8 位的 immediate 值。
(3)由于上面这条指令的译法与我的译法不同,从而导致了 3 条 jmp 指令都不同。
3、 指令 jnz kstrcmp_done 解析
指令 jnz 的 Opcode 是 75,它的描述为 JNZ Jb,它的 operand 是基于 rip 的 8 位 offset 值。
这个 offset 的计算方法是: target = rip + offset 所是: offset = target - rip
★ 由上所得:当前的 rip 为 0x10,而标号 kstrcmp_done 的地址 0x20
★ 所以: offset = target - rip = 0x20 - 0x10 = 0x10
因此:它的 encode 为:75 10
二、 decode
1、这是一段摘自 windows 7 的一段机器码:
fffff800`026ede60 59 65 48 8b 0c 25 20 00 00 00 80 79 20 01 77 72fffff800`026ede70 0f 31 48 c1 e2 20 48 0b c2 48 2b 81 c0 67 00 00
fffff800`026ede80 48 01 81 f8 67 00 00 48 01 81 c0 67 00 00 48 8b
2、看一看它到底是什么代码:
下面我用人工译码:
fffff800_026ede60: 59 pop rcxfffff800_026ede61: 65 48 8b 0c 25 20 00 00 00 mov rcx, qword ptr gs:[0x20]
fffff800_026ede6a: 80 79 20 01 cmp byte ptr [rcx + 0x20], 0x01
fffff800_026ede6e: 77 72 ja .+0x72 *(.表示当前的 rip 值)
fffff800_026ede70: 0f 31 rdtsc
fffff800_026ede72: 48 c1 e2 20 shl rdx, 0x20
fffff800_026ede76: 48 0b c2 or rax, rdx
fffff800_026ede79: 48 2b 81 c0 67 00 00 sub rax, qword ptr [rcx + 0x67c0]
fffff800_026ede80: 48 01 81 f8 67 00 00 add qword ptr [rcx + 0x67f8], rax
fffff800_026ede87: 48 01 81 c0 67 00 00 add qword ptr [rcx + 0x67c0], rax
fffff800_026ede8e: 48 8b ... ...
这里只是纯作译码工作,这里看不出这段代码作用。
下面再看看 ndisasm 译的结果:
00000000 59 pop rcx00000001 65488B0C25200000 mov rcx,[gs:0x20]
-00
0000000A 80792001 cmp byte [rcx+0x20],0x1
0000000E 7772 ja 0x82 *(0x10+0x72=0x82)
00000010 0F31 rdtsc
00000012 48C1E220 shl rdx,0x20
00000016 480BC2 or rax,rdx
00000019 482B81C0670000 sub rax,[rcx+0x67c0]
00000020 480181F8670000 add [rcx+0x67f8],rax
00000027 480181C0670000 add [rcx+0x67c0],rax
0000002E 48 rex.w
0000002F 8B db 0x8b
这里除了显示格式不同外, 结果是完全一样的。
3、来看一看这个 encode:65 48 8b 0c 25 20 00 00 00 应该怎么 decode
(1)65 它是一个 prefix,是 GS - segment override prefix
(2)48 它是一个 REX prefix,REX.W = 1 使用 64 位的 operands,而 REX.R = REX.X = REX.B = 0
(3)8b 它是 Opcode 码,表示:MOV Gv, Ev 即:frist operand 是 registers 而 second operann 是 register/memory,
operand size 是 effective operand size,到目前为止,还不知道 operand 是什么
(4)0c 紧接着 Opcode 码,那么,它就是 ModRM 字节, ModRM = 00-001-100
它提供的 register 是 rcx, ModRM.r/m 提供的寻址是 100 这是 [SIB] 字节,引导出 SIB,因此,下一字节必定是 SIB 字节。
(5)25 由第 (4)步得出,它是个 SIB 字节, SIB = 00-100-101 代表 scale = 00,index = 100, base = 101
由于 index = 100(rsp),因此这里不存在 index 部分,只有 base 部分。
base = 101(rbp),因此它将代表一个 disp32 值,那么,下面接下来的 4 个 bytes 就是 displacement 值
(6)20 00 00 00 这是由第(5)得知,这 4 个 bytes 是 displacement。
----------------------------------------------------------------------------------------
经过上面 6 个步聚的分析,得出最终的汇编指令是:mov rcx, qword ptr gs:[0x20]
上一页 返回目录 下一页
mik(deng zhi)写于 2008-11-26 15:40
- 9. 指令解析
- 指令解析
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令(zz)
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- 解析#pragma指令
- #pragma 预处理指令解析
- 解析#pragma指令
- 解析#pragma指令
- 这些工作真的适合我吗?
- C和指针读书笔记——快速上手
- 堆和栈的区别-两种不同的数据结构
- 7. displacement 值
- 8. immediate 值
- 9. 指令解析
- Android 用户界面---操作栏(Action Bar 一)
- Android 用户界面---操作栏(Action Bar 二)
- Android 用户界面---操作栏(Action Bar 三)
- Android TextView中文字设置超链接、颜色、字体
- 未定义变量报错
- android4.0访问第三方的sharedPreferences数据
- MongoDB Linux下的安装和启动
- 快速阅读很神奇—(一)