1

ここで明らかな何かが欠けている必要がありますが、文字列の終わりを見つけることができないようです.

私のコードは、次のようないくつかの呼び出しから始まります。

; read user input
;
    mov     eax, SYSCALL_READ       ; read function
    mov     ebx, STDIN              ; Arg 1: file descriptor
    mov     ecx, buf                ; Arg 2: address of buffer (buffer is input)
    mov     edx, BUFLEN             ; Arg 3: buffer length (defined as 256)
    int     080h

    mov     [rlen], eax             ; save length of string read

教授は私たちに作業用のシェル プログラムをくれましたが、私はそのほとんどをうまく処理できました。私をうんざりさせているのは、使用している文字列の長さが rlen に含まれるようになったという印象でしたが、次のように入力すると:

mov     byte[esi + rlen], 92            ; add a zero

セグメンテーション違反が発生します。[buf + rlen] を使用した場合も同様です。buf も ESI も単独では segfault を引き起こさないので、rlen は私が思っていることをしていないように思えます。

何が起こっているのかを理解するのを手伝ってくれる人はいますか?

4

1 に答える 1

2

コードに関する 2 つの問題:

mov     byte[esi + rlen], 92
  • 92 != 0. 終端の 0 バイト は'\0'、値が 0 の整数です。

  • rlen はアドレスであり、そのアドレスの値ではありません。

したがって、読み取りが >= 0 を返したことをテストしてから、まだレジスタにある戻り値を使用します。

; read(2) return value still in eax

test eax, eax
jl  read_error    ; handle errors on eax less than zero.

mov esi, buf      ; mov imm32 to get the address in a register

mov  [rlen], eax  ; store return value to the rlen global

mov  byte ptr[esi + eax], 0
;or:  mov byte ptr [buf + eax], 0  ; works because the buffer is statically allocated.

jz  handle_EOF    ; flags still set from test

または、read システム コールによって破壊されていないレジスタに ecx をコピーした場合は、リロードする代わりにそれを使用できます。

関数内では、ローカル変数はレジスター内にあると考えてください。メモリーの場所は、レジスターが不足した場合にそれらをスピルできる場所に限られます。最適化しないコンパイラのようにならないようにして、必要のないときに変数を保存/再読み込みしてください。これは、16 regs の x86-64 のようなアーキテクチャではより簡単です。32 ビット x86 はかなり制限されており、廃止された args-on-the-stack ABI があります。


バッファーが既にゼロになっている場合は、read(2) にバッファー サイズより 1 小さいカウントを渡すだけで済みます。ただし、読み取りが返された後に最後のバイトだけをゼロにする方が良いです。

于 2015-09-30T11:31:02.007 に答える