アセンブラでエンディアン変換してみます。
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)


コメント