x86環境でアセンブラ(NASM)の学習を始めています。  
サブルーチンの書き方を学ぼうと思い、下部のコードを記載してみています。  
期待している結果としては、

```

    Hello, World
    Japan
    
```

と、出力させたいのですが、下部のコードを実行すると、以下のように出力されます。

```

    Hello, World
    Japan
    Japan
    
```

イメージとしては、17行目callでtestのサブルーチンを実行していることでJapanを出力させる処理を走らせていると思っているのですが、実際にはcallが無くても「test:」部を実行しているようです。  
どのようにコーディングすればサブルーチンとしてのみ動作させられるでしょうか？

```

      1 section .data
      2 message db 'Hello, World', 0x0a
      3 message2 db 'Japan', 0x0a
      4
      5 length      equ $ -message
      6 length2         equ $ -message2
      7 section .text
      8 global _start
      9
     10 _start:
     11         mov     ecx, message
     12         mov     edx, length
     13         mov     eax, 4
     14         mov     ebx, 1
     15         int     0x80
     16
     17         call test
     18
     19         mov     eax, 1
     20         mov     ebx, 0 
     21         int     0x80
     22
     23         test:
     24                 mov     ecx, message2
     25                 mov     edx, length2
     26                 mov     eax, 4
     27                 mov     ebx, 1
     28                 int 0x80
     29                 ret
    
```
CC BY-SA 3.0
2016-08-13T15:20:43.627
28238
2016-08-13T16:10:25.297
18444
question
linux
アセンブラ(NASM)のサブルーチンの書き方について
あなたのコードのメインルーチンの最後には、

```

     19         mov     eax, 1
     20         mov     ebx, 0 
     21         int     0x80
    
```

と、sys_exitの呼び出しが含まれていますから、それを超えてサブルーチン`test`の部分が実行されてしまうことはないはずです。  
(ebxに値を設定する必要はないように思うのですが、とりあえずあっても無害のはずです。)

Japanが2回表示される原因はこちらです。

```

      2 message db 'Hello, World', 0x0a
      3 message2 db 'Japan', 0x0a
      4
      5 length      equ $ -message
      6 length2         equ $ -message2
    
```

この定義ですと、`length`には`message`の最初から現在位置(`$`)までの長さを計算していることになりますから、その長さには`message2`というラベルを通り越して'Hello,
World', 0x0a, 'Japan', 0x0aまで全部が含まれることになります。

```

     11         mov     ecx, message
     12         mov     edx, length
     13         mov     eax, 4
     14         mov     ebx, 1
     15         int     0x80
    
```

その結果、メインルーチンの上記処理を実行するとJapanの部分まで表示されることになります。

あなたの所望の動作をさせるには、先の2行目から6行目までを次のように書き直してください。

```

      2 message db 'Hello, World', 0x0a
      3 length      equ $ -message
      4
      5 message2 db 'Japan', 0x0a
      6 length2         equ $ -message2
    
```

これで`length`は'Hello, World', 0x0aの部分だけを表すようになります。

これから学習されるんなら64ビットコードの方が良いんじゃないかとか、`int
0x80`なんてのは古い書き方だとか、今時全部をアセンブラーで書くことはないから早めにCコンベンションのサブルーチンの書き方を覚えたほうが良いんじゃないかとか、いろいろ突っ込みどころはあるんですが、おいおい学習していってください。
CC BY-SA 3.0
2016-08-13T16:10:25.297
28240
2016-08-13T16:10:25.297
13972
28238
answer