

[アセンブリでプログラムが終了してしまう](https://ja.stackoverflow.com/questions/28668/%e3%82%a2%e3%82%bb%e3%83%b3%e3%83%96%e3%83%aa%e3%81%a7%e3%83%97%e3%83%ad%e3%82%b0%e3%83%a9%e3%83%a0%e3%81%8c%e7%b5%82%e4%ba%86%e3%81%97%e3%81%a6%e3%81%97%e3%81%be%e3%81%86)
の質問を投稿したものです  
アセンブリでbmi(Body Mass Index) を計算するプログラムを練習のために書いているのですが途中でsegmentation
faultを出して止まってしまいます。

なぜなのでしょうか?

OS: ubuntu16.04 x86_64  
gcc `-m32`をつけて32bitとしてコンパイル

[code]

    
    .data
    emessage: .string "file open error\n"
    your_height: .string "Please enter the your height  (m):  "
    your_weight: .string "Please enter the your weight  (kg):  " 
    newline: .string "\n"
    
    .bss
    tmp: .skip 128, 0x00
    
    .text
    .global main
    main:
        push %ebp
        movl %esp, %ebp
        pushl $your_height
        call print
        call read
        pushl $your_weight
        call print
        call read
        movl %esp, %eax
        movl 20(%esp), %ebx
        divl %ebx
        divl %ebx
        pushl %eax
        call print
        call exit
    
    
    read:
        movl $3, %eax
        movl $0, %ebx
        movl $tmp, %ecx
        movl $64, %edx
        int $0x80
        cmpl $-1, %eax
        je write_error_message
        movl $tmp, %esi
        pushl %esi
        ret
    
    write_error_message:
        movl $4, %eax
        movl $1, %ebx
        movl $emessage, %ecx
        movl $16, %edx
        int $0x80
        call exit
    
    exit:
        movl $1, %eax;
        xorl %ebx, %ebx;
        int $0x80
    
    print:
        movl $4, %eax
        movl 4(%esp), %ecx
        movl $1, %ebx
        movl $1, %edx
    write:
        cmpb $0x00, (%ecx)
        je ret_func
        movl $4, %eax
        int $0x80
        incl %ecx
        jmp write
    
    
    ret_func:
        ret
    
    
[/code]


CC BY-SA 3.0
2016-09-05T13:28:49.033
28706
2016-11-27T08:26:40.980
2017-04-13T12:52:38.920
-1
5246
question
assembly
アセンブリがsegmentation faultで止まる


直接の原因は `read` でスタックフレームを破壊している状態で `ret` しているためです。  
そこを修正すれば直る・・・と言いたいところですがそれだけでは期待したものにならないでしょう。

システムコール `read()` はファイルデスクリプタからバイト列を得るものです。  
`123<改行>` に対して得られる結果は `31` `32` `33` `0A` ですから  
身長・体重の｢数値」を入力する目的には更に `atoi` とか `atof` 相当の処理が必要です。  
提示コードの落ちる原因である `pushl %esi` はおそらく関数呼び出し命令列の一部で  
あろうと推測されますが、不完全なのでプログラムそのものがそこで死んでいます。

[c](/questions/tagged/c "'c' のタグが付いた質問を表示") コンパイラとか `C Runtime Library`
が目の前にあって即使える状況では、  
オイラは `atoi` `strtol` 相当の関数を直接アセンブラで書きたくありません。  
（[c](/questions/tagged/c "'c' のタグが付いた質問を表示")
で相当関数を書いたことはあります。整数演算だけなのでたいして難しくない）  
`atof` `strtod` 相当の関数は [c](/questions/tagged/c "'c' のタグが付いた質問を表示")
であっても書きたくないです。ましてやアセンブラをや。  
（精度落ちとか丸めとか考慮する内容がいっぱいありすぎる）

ここは [c](/questions/tagged/c "'c' のタグが付いた質問を表示") ライブラリ関数を呼び出す手順を学んでみてはいかがでしょうか。  
それはそのまま [c](/questions/tagged/c "'c' のタグが付いた質問を表示")
関数から呼ばれるアセンブラ関数を作る知識にもなります。  
現代的にはアセンブラだけで完結するソフトを作るのは非常に稀だと思います。

x86 の｢関数呼び出し規約」は cdecl や stdcall などいっぱいあるので厄介です。  
最初は [c](/questions/tagged/c "'c' のタグが付いた質問を表示") コンパイラの書き出すアセンブラを読んでみるのがよいでしょう。  
最適化を(強く）かけると熟練者にも読めなくなりますから、最適化なしをお勧めします。

[code]

    gcc -S -O0 example.c
    
[/code]


CC BY-SA 3.0
2016-09-08T05:07:32.807
28759
2016-09-08T05:07:32.807
8589
28706
answer