質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

アセンブリ言語でscanfを使いたいです。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 751

kazuyakazuya

score 153

アセンブリ言語でC言語のscanf関数つまり
ただ受け取るだけのプログラムを作ってみたいです。

とりあえず、見本がないと厳しいので

Cのコードをアセンブラファイルに出力してみました。

#include <stdio.h>

int main(void){
  char sample[10];
  scanf("%s",sample);
  return 0;
}

.file    "scanf.c"
    .def    ___main;    .scl    2;    .type    32;    .endef
    .section .rdata,"dr"
LC0:
    .ascii "%s\0"
    .text
    .globl    _main
    .def    _main;    .scl    2;    .type    32;    .endef
_main:
LFB10:
    .cfi_startproc
    pushl    %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    andl    $-16, %esp
    subl    $32, %esp
    call    ___main
    leal    22(%esp), %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _scanf
    movl    $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE10:
    .ident    "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0"
    .def    _scanf;    .scl    2;    .type    32;    .endef

scanf関数は・・・参考サイトより

scanf("変換指定子", &変数名)

より、変数名(変数のアドレス)・変換指定子

この順番でスタックに積んだ後

callで_scanfを呼べば、標準入力を使うことができると考えました。

で、私が作ってみた(少し変えただけ)コード

  .text
  msg: .ascii "%s\0";     // %s が置いてあるアドレス
       .globl _main

 _main:

  subl  $12,%esp//スタック領域確保
  //ここで sample が置かれているアドレスを・・・movlする
  movl  $msg,8(%esp)
  call _scanf
  add   $12, %esp
  ret


sample変数「配列」のアドレスをスタックに積みたいのですが

アドレスの求め方がわかりません。

Cからコンパイルした結果を見ると

leal    22(%esp), %eax
movl    %eax, 4(%esp)

それでも、"sample"と書かれている場所はありませんが・・・。

char sample[10];

の場所(アドレス)はどうやったら求められるのか、

アセンブリ出力ファイルでいうところでは

どこなのかについて教えてください。

以下解決コード

 .text
  msg: .ascii "%s\0";
  msg2: .ascii "Repeat 1 times\n\0";
       .globl _main

_main:

  subl  $20,%esp
  leal  8(%esp), %eax #12bytes can be input.
  movl  %eax, 4(%esp)
  movl  $msg,(%esp)
  call _scanf

  subl $15,%esp
  movl $msg2,4(%esp)
  movl $msg,(%esp) #printf("%s",sample);
  call _printf
  add  $15,%esp

  call _printf
  add $20,%esp
  ret
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • kazuyakazuya

    2019/10/25 08:05

    ありがとうございます。

    やっぱ前提知識がなくて

    システムコール・ライブラリ・Windows・Linux・dll

    などなど認識がめちゃめちゃなので

    調べなおします。(聞き直します。)

    キャンセル

  • rubato6809

    2019/10/25 08:30

    実は私はWindowsのシステムコールとかDLLとか馴染みが無いです。
    Windows関係のタグで質問してみるのも手でしょうね。

    キャンセル

  • kazuyakazuya

    2019/10/25 08:42

    基礎的なことは知恵袋のほうで済ませようと思います。

    システムコールの話になるとwindowsとかのOSも

    関係しそう(てか、関係する)なのでタグはつけようと思います。

    キャンセル

回答 2

checkベストアンサー

+1

    andl    $-16, %esp
    subl    $32, %esp
    call    ___main
    leal    22(%esp), %eax
    movl    %eax, 4(%esp)  # オフセット4に sample 配列の先頭アドレス
    movl    $LC0, (%esp)   # スタックトップ(オフセット0)に "%s"
    call    _scanf         # scanf("%s", sample);

subl $32, %esp した直後から、スタックトップから32バイトは、この関数が自由に使えるローカル変数領域です。32 = 4 + 4 + 14 + 10 ですから、回答を修正しますとスタックトップから

  • 4バイト: "%s" 文字列のアドレス、scanf() の第一引数
  • 4バイト: 配列 sample のアドレス、scanf() の第二引数
  • 14バイト: 今のところ何にも使われていない領域
  • 10バイト: char sample[10] 用の領域

と割り当てています。これがわかれば leal 22(%esp), %eax が sample 配列の先頭アドレスを求めているとわかります。

ローカル変数は「スタックポインタ+オフセット」が、その変数のアドレスになることを、当然ながらコンパイラは分かったうえでコードを生成するので、アセンブリコードに変数名を出力することは、まずありません。

P.S.
コンパイルが通っただけでは正しい動作にならないことがたくさんあったはずです。動作しているように見えても、実はおかしな動作をしていた、という経験はありませんでしたか?scanf() が正しく動作したとは、入力したものが期待どおりに変数に格納されたかどうか、結果を確認できて初めて動作できたと言えます。例えば

    char buffer[10];
    scanf("%s", buffer);      // 入力したものが
    printf("[%s]\n", buffer); // 格納されたか確認


アセンブリ言語で書いたコードが正しくscanf()を呼べたかどうかも、やはり同じように結果を確認する必要があります。キーボードでタイプできた、というだけでは正しく動作できたことを意味しません。
結果を表示させて確認する、そのためにC言語ではprintf()から学び始めますね。アセンブリ言語の動作確認をするにも、まずはアセンブリコードで表示して確認する手段を手にいれることが大事です。それには

  • printf() にパラメータを渡して表示させる手段
  • Cで自分が書いた表示関数に、手際よく必要なデータを渡す手段

などを、まずは調査することをお勧めしたいと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/24 08:23 編集

    訂正しました。

    キャンセル

  • 2019/10/24 09:13

    了解。2つめの call print が肝心で、ひとつ目はprintfのテストみたいなものですね。

    キャンセル

  • 2019/10/24 16:01

    操作ミスりました。

    キャンセル

+1

char sample[10];
の場所(アドレス)はどうやったら求められるのか、  

ローカル変数なので、スタックに確保されてる(はず)なんで、コードを読んでいきましょう
がんばってくださいw

#コレはアセンブラの話じゃなくて、C言語の話ですわな

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/24 12:48

    うーん、わかりました。

    キャンセル

  • 2019/10/24 15:23

    私から見ても今の時点では不可能に見えます。動作した事例と全く同じ条件を揃えれば真似るだけだが、現実のターゲットには様々な相違点があるので、わけもわからず真似ても動作しません。何が違いなのか(何は違っても構わないのか)、どんなハードルがいくつ待ち受けているのか、ハードルを超えるにはどうすればよいか、何をどう確認すれば個々のハードルを越えたと言えるのか、見えていないと思う。

    > call _printfしているところ?

    その辺りの機械語と文字列を元にしてアレンジした数十バイトにも満たない機械語は "hello world" を表示するシェルコードになりうると思います。シェルコードとは、目的の動作をする、正味の機械語、といった意味でしょう。
    そのままでは、まずダメと思う。アレンジが必要。でも動作環境・条件・目的・理由を精度よく把握できないと適切なアレンジはできない。シェルコードを作るためのツールなど無いのだから、工夫も要る。
    例えば "call _printf" 命令は、普通シェルコードでは使いものになりません。その理由が分かりますか?絶対使えない、とも言えないが、じゃ使える条件は何か?となる。

    さらに、今時のOSだとスタック領域でプログラムが走らないようにガードをかけているはずなので、首尾よくシェルコードを文字配列に上書きできたとしても、そこ(スタック領域だよね)では動作できないでしょう。これもハードル・・・というか、そもそもハードルになっているかどうか確認しただろうか?それは、その確認方法がわかるか?という問いにもなる。
    確認すべきことがまだ幾つかあると思う、先は長いよ笑。プラモデルの組立てとは違うので、機械語レベルの動作まで理解せずにハッキングは不可能。Cだけで書ける書けないは、何が必要なのかが見えてないと検討のしようがない。

    キャンセル

  • 2019/10/24 17:16

    まずは・・・
    ①ライブラリのリンクの問題
    ②スタックの位置の把握

    でしょうか・・・?(https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q12215345702?fr=chie_my_notice_newans
    聞いただけだけど・・・)

    まずはライブラリの問題から手を付けようと思います。

    (それでもハードル高そうだけど)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る