

[nasmで1~100まで数える - Qiita](https://qiita.com/akakou/items/fb42e0dbfe9e5dc0a588)

上記の記事を参考に次のコードを実行しますとエラーが返されました。調べたところオプションを設定する必要があるとかないとかのようですがよくわかりません、よろしくお願いします

[code]

    extern printf                  ; printf関数を持ってくる
    
    section .data
        fmt: db "iteration: %d", 10, 0         ; printfで用いるフォーマット
    
    section .text
        global _main
    _main:
        mov rdx, 1                  ; 初期値
        mov rcx, 10
    
    _loop:
        push rcx                  ; rcxの避難
        push rdx                  ; rdxの避難
    
        mov rdi, fmt                ; フォーマット
        mov rsi, rdx                ; カウントしている値
    
        call printf               ; printfをコール
        ; printfのコール時にレジスタの値が消えてしまう
    
        pop rdx                  ; rdxを持ってくる
        pop rcx                  ; rcxを持ってくる
    
        add rdx, 1               ; rdxに１加算
    
        cmp rcx, 0
        loop _loop                  ; ループバック
    
    fin:
        mov rax, 0x2000001
        mov rdi, 0
        syscall
    
[/code]

エラー

[code]

     $ ld -macosx_version_min 10.14 -lSystem -o p100 p100.o
        Undefined symbols for architecture x86_64:
         "printf", referenced from:
              _loop in p100.o
          ld: symbol(s) not found for inferred architecture x86_64
    
[/code]

また、

[code]

    mov rsi, rdx
    
[/code]

としている理由がわかりません


CC BY-SA 4.0
2019-05-06T12:30:56.160
54778
2019-05-07T04:51:53.683
2019-05-06T15:41:28.040
3060
question
x86
Undefined symbols for architecture x86_64: "printf" ld: symbol(s) not found for inferred architecture x86_64


`Undefined symbols` の原因は `ld` が `libSystem.dynlib`
を見つけることに失敗しているんだと思います（憶測：間違っている可能性大）。要するに `ld` に対するオプション `-L`
が足らないんでしょう。オイラんとこには Mac 無いので具体的にどうすればよいかはわかりません。

`mov rsi, rdx` が必要なのは `x86-64` Application Binary Interface (ABI)
仕様がそのように求めているからです。詳しく説明すると本１冊になっちゃうので  
<https://en.wikipedia.org/wiki/X86_calling_conventions>  
の System V AMD64 ABI あたりから参照のこと。

あなたのプログラムは `rcx` と `rdx` をレジスタ変数として使っているのですが ABI 仕様により、関数 (この例では `printf`)
を呼び出す際の引数に `rcx` や `rdx` を使うことが定められているので、提示のように `push` / `pop` が必要となります。

と、言いたいところなんですが

提示プログラムは `x86-64 ABI`
のレジスタ保存規則ならびにスタック仕様を満たしていないので正しく動きません。今動いているとしたら偶然です（障害が顕在化してないだけ）。  
[なぜrcxをpushする必要があるのか？](https://ja.stackoverflow.com/questions/54768/)  
でもレジスタ保存規則、スタック仕様を満たしていないので、動いているのは偶然です（指摘しようかなと思ったけど本筋でないので略したっす）。

現代 `ABI` はコンパイラを使う前提で設計されていて、アセンブラを手書きすることはほとんど全く想定されていません。関数は（この例では `main`
が）その入口と出口で決められた仕様を満たすコードを必ず実装しなければならないことになっています。コンパイラなら忘れずに実装できますが、アセンブラ手書きだととても面倒。この辺の規約ならびに
CPU の仕様を熟知した人間でないとアセンブラ手書きは実装コストに合いません。

本職でないのなら `x86-64`
アセンブラの手書きを覚えるなどまったくもって遠回りで、学習コストのみ高くついて、でも得られるものが少ないです。オイラの後輩君がアセンブラ手書きを覚えたいと言ったなら一度は止めさせます（既にそれなりの知識があってかつ興味もあるのであれば
GO させるでしょうが）本当にその必要があるのかどうかゆっくり検討してみてください。


CC BY-SA 4.0
2019-05-07T04:51:53.683
54791
2019-05-07T04:51:53.683
8589
54778
answer