Category Archives: 9-1.ソース・ビルド・インストール

アセンブラでエンディアン変換

アセンブラでエンディアン変換してみます。
32bitの変数aのエンディアン変換です。EAXとEBXレジスタを使います。
まずは1Byteのコピーから。

takk@deb9:~/tmp$ cat -n t.c
     1  #include <stdio.h>
     2  int main()
     3  {
     4          unsigned long a;
     5          asm("movq $0x12345678,-0x8(%rbp)");
     6          asm("mov -0x8(%rbp), %eax");
     7          asm("mov $0,%ebx");
     8          asm("mov %al,%bl");
     9          asm("mov %ebx,-0x8(%rbp)");
    10          printf("%08x\n",a);
    11  }
takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
00000078
takk@deb9:~/tmp$

コピーして8bitシフトします。

takk@deb9:~/tmp$ cat -n t.c
     1  #include <stdio.h>
     2  int main()
     3  {
     4          unsigned long a;
     5          asm("movq $0x12345678,-0x8(%rbp)");
     6          asm("mov -0x8(%rbp), %eax");
     7          asm("mov $0,%ebx");
     8          asm("mov %al,%bl");
     9          asm("shl $8,%ebx");
    10          asm("mov %ebx,-0x8(%rbp)");
    11          printf("%08x\n",a);
    12  }
takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
00007800
takk@deb9:~/tmp$

これを繰り返します。

takk@deb9:~/tmp$ cat -n t.c
     1  #include <stdio.h>
     2  int main()
     3  {
     4          unsigned long a;
     5          asm("movq $0x12345678,-0x8(%rbp)");
     6          asm("mov -0x8(%rbp), %eax");
     7          asm("mov $0,%ebx");
     8
     9          asm("mov %al,%bl");
    10          asm("shl $8,%ebx");
    11          asm("shr $8,%eax");
    12
    13          asm("mov %al,%bl");
    14          asm("shl $8,%ebx");
    15          asm("shr $8,%eax");
    16
    17          asm("mov %ebx,-0x8(%rbp)");
    18          printf("%08x\n",a);
    19  }
takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
00785600
takk@deb9:~/tmp$

8bitシフトを3回繰り返して、最後の最下位1Byteをコピーすれば、エンディアン変換完了です。

takk@deb9:~/tmp$ cat -n t.c
     1  #include <stdio.h>
     2  int main()
     3  {
     4          unsigned long a;
     5          asm("movq $0x12345678,-0x8(%rbp)");
     6          asm("mov -0x8(%rbp), %eax");
     7          asm("mov $0,%ebx");
     8
     9          asm("mov %al,%bl");
    10          asm("shl $8,%ebx");
    11          asm("shr $8,%eax");
    12
    13          asm("mov %al,%bl");
    14          asm("shl $8,%ebx");
    15          asm("shr $8,%eax");
    16
    17          asm("mov %al,%bl");
    18          asm("shl $8,%ebx");
    19          asm("shr $8,%eax");
    20
    21          asm("mov %al,%bl");
    22
    23          asm("mov %ebx,-0x8(%rbp)");
    24          printf("%08x\n",a);
    25  }
takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
78563412
takk@deb9:~/tmp$

ポインタを使ってエンディアン変換すると、こんな感じでしょうか。

takk@deb9:~/tmp$ cat -n t.c
     1  #include <stdio.h>
     2
     3  int main()
     4  {
     5          unsigned long a;
     6          unsigned char *p;
     7          unsigned char tmp[4];
     8          a = 0x12345678;
     9          p = (unsigned char*)&a;
    10          tmp[3] = *p++;
    11          tmp[2] = *p++;
    12          tmp[1] = *p++;
    13          tmp[0] = *p++;
    14          a = *(unsigned long*)tmp;
    15          printf("%08x\n",a);
    16  }
takk@deb9:~/tmp$ gcc t.c
takk@deb9:~/tmp$ ./a.out
78563412
takk@deb9:~/tmp$

アセンブラにすると、長いコードになります。ポインタによるエンディアン変換はとても非効率なようです。

00000000000006b0 <main>:
 6b0:   55                      push   %rbp
 6b1:   48 89 e5                mov    %rsp,%rbp
 6b4:   48 83 ec 20             sub    $0x20,%rsp
 6b8:   48 c7 45 f0 78 56 34    movq   $0x12345678,-0x10(%rbp)
 6bf:   12
 6c0:   48 8d 45 f0             lea    -0x10(%rbp),%rax
 6c4:   48 89 45 f8             mov    %rax,-0x8(%rbp)
 6c8:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 6cc:   48 8d 50 01             lea    0x1(%rax),%rdx
 6d0:   48 89 55 f8             mov    %rdx,-0x8(%rbp)
 6d4:   0f b6 00                movzbl (%rax),%eax
 6d7:   88 45 ef                mov    %al,-0x11(%rbp)
 6da:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 6de:   48 8d 50 01             lea    0x1(%rax),%rdx
 6e2:   48 89 55 f8             mov    %rdx,-0x8(%rbp)
 6e6:   0f b6 00                movzbl (%rax),%eax
 6e9:   88 45 ee                mov    %al,-0x12(%rbp)
 6ec:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 6f0:   48 8d 50 01             lea    0x1(%rax),%rdx
 6f4:   48 89 55 f8             mov    %rdx,-0x8(%rbp)
 6f8:   0f b6 00                movzbl (%rax),%eax
 6fb:   88 45 ed                mov    %al,-0x13(%rbp)
 6fe:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 702:   48 8d 50 01             lea    0x1(%rax),%rdx
 706:   48 89 55 f8             mov    %rdx,-0x8(%rbp)
 70a:   0f b6 00                movzbl (%rax),%eax
 70d:   88 45 ec                mov    %al,-0x14(%rbp)
 710:   48 8d 45 ec             lea    -0x14(%rbp),%rax
 714:   48 8b 00                mov    (%rax),%rax
 717:   48 89 45 f0             mov    %rax,-0x10(%rbp)
 71b:   48 8b 45 f0             mov    -0x10(%rbp),%rax
 71f:   48 89 c6                mov    %rax,%rsi
 722:   48 8d 3d 9b 00 00 00    lea    0x9b(%rip),%rdi        # 7c4 <_IO_stdin_used+0x4>
 729:   b8 00 00 00 00          mov    $0x0,%eax
 72e:   e8 2d fe ff ff          callq  560 <printf@plt>
 733:   b8 00 00 00 00          mov    $0x0,%eax
 738:   c9                      leaveq
 739:   c3                      retq
 73a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)