トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

アセンブラ(システムコール)

[アセンブラ]

アセンブラの学習

前回まででとりあえずインラインアセンブラで変数宣言とかできた。次はHello,World!!したい。

システムコール

これを呼べばOSの力を借りて標準出力できる。アセンブラ独力でやるのはしんどいので後で… アセンブラ独力では無理だ

システムコールとは、オペレーティングシステム (OS)(より明確に言えばOSのカーネル)の

機能を呼び出すために使用される機構のこと。実際のプログラミングにおいては、OSの機能は関数 (API)

呼び出しによって実現されるので、OSの備える関数 (API) のことを指すこともある。

  さてさて

ここまででたぶんお分かりかもしれないが、アセンブラはCPUのアーキとOSに依存する。

CPUのアーキ OS
i386 や x86_64 Linux/Windows/BSD .etc...
レジスタの使い方や種類が違う システムコールの種類や使い方が違う

やっぱりC言語って便利だったんすね~、JavaとかC#に至っては神に見える

  Linuxのシステムコール

オンラインコンパイラを使いたいのでLinuxを中心に攻めていく、以下は下記のサイトの翻訳となる

32-bit Linuxにおけるシステムコール

  • 32bitのLinuxでシステムコールを実行する場合、システムコールの番号をレジスタのeaxに置き、その引数を順番にebx, ecx, edx, esi, ediそしてebpに置き、intの0x80を呼び出します
  • 返り値に情報を返してくるシステムコールもあります、返り値はeaxに入ります
  • すべてのレジスタはシステムコールを通じて保存されます

64-bit Linuxにおけるシステムコール

  • 64bitのLinuxでシステムコールを実行する場合、システムコールの番号をレジスタのraxに置き、その引数を順番にrdi, rsi, rdx, r10, r8そしてr9に置き、syscallを呼び出します(※x86と違ってそのまんまなんですな)
  • 返り値に情報を返してくるシステムコールもあります、返り値はraxに入ります。-4095~-1の範囲の値はエラーを示します、つまりC言語で言う-errnoです。
  • システムコールはレジスタのrcxとr11を破壊しますが、残りのレジスタはシステムコールを通じて保存されます
  • 詳細はこのThe AMD64 ABIから

Linuxのシステムコール一覧

これらのページを確認し、そして当然ですがLinuxのソースコードも見て下さい。

めんどくさい…

  Hello,World

アセンブラソースを修正

先ほどのページに生のアセンブラが書いてあるので、それを修正してみよう

# ----------------------------------------------------------------------------------------
# Writes "Hello, World" to the console using only system calls. Runs on 64-bit Linux only.
# To assemble and run:
#
#     gcc -c hello.s && ld hello.o && ./a.out
#
# or
#
#     gcc -nostdlib hello.s && ./a.out
# ----------------------------------------------------------------------------------------

        .global _start

        .text
_start:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        mov     $message, %rsi          # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall                         # invoke operating system to do the write

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # we want return code 0
        syscall                         # invoke operating system to exit
message:
        .ascii  "Hello, world\n"

インラインアセンブラ版(C言語)

  • オペランド制約をきっちり記述しないとHelloWorldが出ないようです
#include <stdio.h>
#include <unistd.h>

int main()
{
    const char hello[] = "Hello World!\n";
    const size_t hello_size = sizeof(hello);
    unsigned int ret;

    __asm__ volatile (
        "mov $1, %%rax    \n\t"
        "mov $1, %%rdi    \n\t"
        "mov %1, %%rsi    \n\t"
        "mov %2, %%rdx    \n\t"
        "syscall"
        : "=a"(ret)
        : "S"(hello), "d"(hello_size)
    );

    return 0;
}

システム言語の意義とは

  • C言語はC言語でソースコードを書くと、それをアセンブラに変換し、動く機械語に変換する。
  • 動く機械語とはバイナリと呼ばれるものである。OSはバイナリをCPUに渡し、実行結果を受け取る。
  • プログラミング言語の世界で、このバイナリを吐ける言語をシステム言語と呼んだりする。それはC言語を筆頭として、C++、D言語、Go言語などを指す。
  • すでに、CPUのプラットフォームとOSのプラットフォームが固定化された世界では、アセンブラでコーディングすることは労力がかかるために意味をなさないことが多い。
  • だから、「アセンブラで最適化した〜」とか、そういう言説や人はあまり信用できない(と、管理人は思う)
  • 言いたいことはつまり、ソースコードから機械語への変換を助けて最適化するのがシステム言語の役割であり、それを人手でやるのは非効率であるということだ。
  • でも、新たにシステム言語を作ったり、OSを一から書く場合アセンブラは避けては通れない気がします。

お名前: コメント: