0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アセンブリ言語 strlenを書いてみる

Last updated at Posted at 2021-04-05

アセンブリを書いてみる

アセンブリ言語はOSごとに異なっており、リファレンスも検索性が高いものがありません。
まともにリファレンスの情報をベースに実装していくのはとても困難な作業です。既存のまとめの継ぎ接ぎになってしまった感は否めなせんが、自分のメモとして残します。

主に参考にしたのは以下のサイトです。

環境

$ uname -a
Darwin user-pc.local 20.3.0 Darwin Kernel Version 20.3.0: Thu Jan 21 00:07:06 PST 2021; root:xnu-7195.81.3~1/RELEASE_X86_64 x86_64

$ sw_vers
ProductName:	macOS
ProductVersion:	11.2.3
BuildVersion:	20D91

$ nasm -v
NASM version 2.15.05 compiled on Aug 29 2020

書いたコード

追記 2021/04/23 プロローグ、エピローグの処理を消去

section .text
	global _ft_strlen
_ft_strlen
	xor		rax, rax
.loop:
	cmp		BYTE [rdi + rax], 0
	je		.end
	inc		rax
	jmp		.loop
.end:
	ret

セクション

section .text
    global _ft_strlen

セクションとか.textとか

引数の受け取り

引数の受け取りはレジスタを通して行われます
どのレジスタにどの引数が格納されるかは呼び出し規約というルールで定められているようです。

x86 calling conventions - Wikipedia

引数 レジスタ
第1引数 RDI
第2引数 RSI
第3引数 RDX
第4引数 RCX
第5引数 R8

今回はstrlenなので第1引数のみ使用しています。

xor rax, rax

raxというレジスタに0を入れています。
以下のように書くこともできますが、高速化のためにxorを使っています。

mov rax, 0x0

c++ - bitの初期化は「0代入」と「^(XOR)演算」どちらが速い? - スタック・オーバーフロー

やっていることとしては、int i = 0;みたいなイメージです。

raxとは

汎用レジスタであり、64bitの値を扱うことが可能。
システムコール番号の指定にも使用され、結果が返る場所でもある。

変数的なものと思えばOKです。

cmp BYTE [rdi + rax], 0x0

cmp		BYTE [rdi + rax], 0x0
je		.end

rdi + rax のポインタからBYTE分(1byte分)、0x0と比較し、0x0と等しかった場合、_endにジャンプする。

大かっこでくくるとポインタを表すようになります。

BYTE

参照するアドレスの範囲を指定しています。
指定する範囲は以下のようになります。

指定 | バイト数

  • | -
    BYTE | 1 バイト
    WORD | 2 バイト
    DWORD | 4 バイト
    FWORD | 6 バイト
    QWORD | 8 バイト

cmp

レジスタとレジスタ、レジスタとメモリ内容、レジスタと定数を比較して、結果をフラグに反映させます。
内部的には左側のオペランドから右のオペランドを減算しますが、減算結果は返しません。
通常、条件ジャンプ命令が続きます。

je .end

真だったら(1だったら).endにジャンプ

条件ジャンプ命令

条件ジャンプ命令には様々な種類があります。

命令 ジャンプ条件
JA より上(CF = 0 & ZF = 0)
JAE より上か等しい(CF = 0)
JB より下(CF = 1)
JBE より下か等しい(CF = 1
JC キャリーがある(CF = 1)
JCXZ CXレジスタが0
JE 等しい(ZF = 1)
JG より大きい(ZF = 0 & SF = OF)
JGE より大きいか等しい(SD = OF)
JL より小さい(SF ! OF)
JLE より小さいか等しい(ZF = 1
JNA より上でない(CF = 1
JNAE より上でなく等しい(CF = 1)
JNB より下でない(CF = 0)
JNBE より下でなく等しい(CF = 0 & ZF = 0)
JNC キャリーがない(CF = 0)
JNE 等しくない(ZF = 0)
JNG より大きくない(ZF = 1
JNGE より大きくなく等しくない(SF ! OF)
JNL より小さくない(SF = OF)
JNLE より小さくなく等しくない(ZF = 0 & SF = OF)
JNO オーバーフローがない(OF = 0)
JNP パリティがない(PF = 0)
JNS 符号がない(SF = 0)
JNZ ゼロではない(ZF = 0)
JO オーバーフローがある(PF = 1)
JP パリティがある(PF = 1)
JPE パリティが偶数(PF = 1)
JPO パリティが基数(PF = 0)
JS 符合がある(SF = 1)
JZ ゼロである(ZF = 1)

一覧は以下から引用しました。
インラインアセンブラで学ぶアセンブリ言語 第3回 (1/3):CodeZine(コードジン)

inc

inc		rax

インクリメントです。
i++と同じです。ここではraxの値をインクリメントしています。

jmp

jmp		.loop

_loopにジャンプします。

ret

ret

retは pop ripと同じ意味

呼び出し元に戻るということです。

参考

今回は使っていませんが、インテルのアセンブリに関しては以下の資料集が参考になリます。

リファンレスとしては以下のintelのものが最も適切かと思いますが、PDFのみで検索性も低く使いにくいです。

FreeBSDに固有な実装もあり、リファレンスを探しても見つからないものは以下のサイトを参照したりもしました。

Chapter 11. x86 Assembly Language Programming

ここはある程度検索できるので便利でした。
Microsoft マクロアセンブラーリファレンス | Microsoft Docs

0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?