読者です 読者をやめる 読者になる 読者になる

objdumpのdiffをいい感じに取る方法のメモ

たとえば、次のような二つのC言語コードを考える。

/* test1.c */
#include <stdio.h>

double divide(long x, long y)
{
    return x/(double)y;
}

int main()
{
    divide(1, 2);
    divide(1, 0);
    return 0;
}
/* test2.c */
#include <stdio.h>
#include <stdlib.h>

double divide(long x, long y)
{
    if (!y) {
        exit(1);
    }
    return x/(double)y;
}

int main()
{
    divide(1, 2);
    divide(1, 0);
    return 0;
}

二つ目のコードは、被除数が0かどうかのチェックを加えたものである。 これらをそれぞれコンパイルし、objdumpで逆アセンブルしたもののdiffを取ると次のようになる。

$ make test1 test2
cc     test1.c   -o test1
cc     test2.c   -o test2

$ diff -u <(objdump -d test1) <(objdump -d test2)
--- /dev/fd/63  2016-04-30 07:28:59.852032082 +0900
+++ /dev/fd/62  2016-04-30 07:28:59.852032082 +0900
@@ -1,193 +1,202 @@

-test1:     file format elf64-x86-64
+test2:     file format elf64-x86-64


 Disassembly of section .init:

-00000000004003a8 <_init>:
-  4003a8:      48 83 ec 08             sub    rsp,0x8
-  4003ac:      48 8b 05 45 0c 20 00    mov    rax,QWORD PTR [rip+0x200c45]        # 600ff8 <_DYNAMIC+0x1d0>
-  4003b3:      48 85 c0                test   rax,rax
-  4003b6:      74 05                   je     4003bd <_init+0x15>
-  4003b8:      e8 33 00 00 00          call   4003f0 <__gmon_start__@plt>
-  4003bd:      48 83 c4 08             add    rsp,0x8
-  4003c1:      c3                      ret
+00000000004003e0 <_init>:
+  4003e0:      48 83 ec 08             sub    rsp,0x8
+  4003e4:      48 8b 05 0d 0c 20 00    mov    rax,QWORD PTR [rip+0x200c0d]        # 600ff8 <_DYNAMIC+0x1d0>
+  4003eb:      48 85 c0                test   rax,rax
+  4003ee:      74 05                   je     4003f5 <_init+0x15>
+  4003f0:      e8 2b 00 00 00          call   400420 <__gmon_start__@plt>
+  4003f5:      48 83 c4 08             add    rsp,0x8
+  4003f9:      c3                      ret

 Disassembly of section .plt:

-00000000004003d0 <__libc_start_main@plt-0x10>:
-  4003d0:      ff 35 32 0c 20 00       push   QWORD PTR [rip+0x200c32]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
-  4003d6:      ff 25 34 0c 20 00       jmp    QWORD PTR [rip+0x200c34]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
-  4003dc:      0f 1f 40 00             nop    DWORD PTR [rax+0x0]
-
(snip)

主にアドレス部分のずれにより、まったくdiffが取れていないことがわかる。

このような場合、次のようなコマンドを打つとよい。

$ diff -u1 -F '>:$' -I '[0-9a-f]\{6,\}' <(objdump -d test1 | cut -f2-) <(objdump -d test2 | cut -f2-)
--- /dev/fd/63  2016-04-30 07:40:28.072016196 +0900
+++ /dev/fd/62  2016-04-30 07:40:28.072016196 +0900
@@ -1,3 +1,3 @@

-test1:     file format elf64-x86-64
+test2:     file format elf64-x86-64

@@ -30,3 +30,8 @@ 00000000004003f0 <__gmon_start__@plt>:
 68 01 00 00 00         push   0x1
-e9 d0 ff ff ff         jmp    4003d0 <_init+0x28>
+e9 d0 ff ff ff         jmp    400400 <_init+0x20>
+
+0000000000400430 <exit@plt>:
+ff 25 f2 0b 20 00      jmp    QWORD PTR [rip+0x200bf2]        # 601028 <_GLOBAL_OFFSET_TABLE_+0x28>
+68 02 00 00 00         push   0x2
+e9 c0 ff ff ff         jmp    400400 <_init+0x20>

@@ -118,4 +123,9 @@ 00000000004004ed <divide>:
 48 89 e5               mov    rbp,rsp
+48 83 ec 20            sub    rsp,0x20
 48 89 7d f8            mov    QWORD PTR [rbp-0x8],rdi
 48 89 75 f0            mov    QWORD PTR [rbp-0x10],rsi
+48 83 7d f0 00         cmp    QWORD PTR [rbp-0x10],0x0
+75 0a                  jne    40054e <divide+0x21>
+bf 01 00 00 00         mov    edi,0x1
+e8 e2 fe ff ff         call   400430 <exit@plt>
 f2 48 0f 2a 45 f8      cvtsi2sd xmm0,QWORD PTR [rbp-0x8]
@@ -127,3 +137,3 @@ 00000000004004ed <divide>:
 f2 0f 10 45 e8         movsd  xmm0,QWORD PTR [rbp-0x18]
-5d                     pop    rbp
+c9                     leave
 c3                     ret
@@ -142,4 +152,3 @@ 000000000040051d <main>:
 c3                     ret
-66 2e 0f 1f 84 00 00   nop    WORD PTR cs:[rax+rax*1+0x0]
-00 00 00
+0f 1f 44 00 00         nop    DWORD PTR [rax+rax*1+0x0]

-u1は差分の前後1行のみを表示させるオプション、-F正規表現にマッチする行をセクション見出しとして扱うオプション、-I正規表現にマッチする行のみの差分を除外するオプションである。