アセンブラで扱う文字列
アセンブラで文字列を扱うとき、定数に書き込まないで、strcpy()すると、
こんな感じに、数字が出力されるんですよね。
1819043144
#include <stdio.h>
#inlcude <stdlib.h>
#include <string.h>
int main(void)
{
char *p = (char*)malloc(16);
strcpy(p, "Hell");
printf("%s\n", p);
return 0;
}
上記のコードを、
gcc -masm=intel -S test.c
すると、下記のようなアセンブリが出力されます。
この数字の意味が知りたくて調査してました。
ポインタを使うと、ラベルがついてそのラベルにアクセスるみたいな感じになると思いますが、
文字列リテラル 'Hell' を
strcpy(destination, "Hell");
すると、謎の数字に変換されちゃうんです。
mov DWORD PTR [rax], 1819043144
と出力され、Hellと書いたはずの文字列が数字に変換されているようです。
かなり苦戦しましたが、決着しました。
mov DWORD PTR 8[rax], 1819043144
mov edi, 16
call malloc@PLT
mov QWORD PTR -8[rbp], rax
mov rax, QWORD PTR -8[rbp]
mov DWORD PTR [rax], 1819043144
mov BYTE PTR 4[rax], 0
mov rax, QWORD PTR -8[rbp]
mov rdi, rax
call puts@PLT
mov eax, 0
leave
ret
定数の1819043144は、16進数の'6c6c6548'を32ビットの整数に収まるように十進数に変換したもので、Cのコードからのアセンブリコードへの変換の過程を以下に示します。
1...
'Hell' -----> 16進数で'48656c6c'
2...
リトルエンディアンにバイトオーダーを変換すると
'48656c6c' -----> '6c6c6548'
3...
'Hell' はアスキーで4文字です。
私のマシンの処理系で、int は 4バイトなので、'Hell'までは int に収まります。
なので、'6c6c6548' は、
QWORDに収まるということですね。
ここ間違いなんですが、
DWORDです。4バイトなのでDWORDです。
DWORDに収まるということですね。に訂正いたします。
4...
計算していきます
6 * 16^7 = 1,610,612,736
c * 16^6 = 201,326,592
6 * 16^5 = 6,291,456
c * 16^4 = 786,432
6 * 16^3 = 84,576
5 * 16^2 = 1,280
4 * 16^1 = 64
8 = 8
1,819,043,144
になるということになります。
確認が取れてないんですが、
mov BYTE PTR 4[rax], 0
は、Null文字じゃないかと思っています。
でも、ちょっと変なんですが、
最初、'Hello'で調査してたんですが、5文字あるので int に収まらないかなと思って、'Hell'(地獄)に変えてアセンブリ変換しては動かすという調査をしていました。
でも、'Hello'で出力すると、
mov BYTE PTR 4[rax], 111
//間違いです。
mov WORD PTR 4[rax], 111
//に訂正いたします
//'o'を一文字付加するだけなので、BYTE でも行けるんじゃないかな?と思ってやった跡が残ってしまっていたようです。
が付きます。
Null文字はそのあとに付加されないんですよね。
二文字、たとえば"oo"を付けて、Null文字らしきものが再度ついていれば、断定できるかもしれません。
111 = 0x6f
0x6f = 'o'
確かに、'Hello'となりますが、なんですかね?
アセンブラ、ムズイです。