2015-09-30 3 views
1

Мне здесь не хватает чего-то очевидного, но я не могу найти конец строки.Руководство по Null-Termination в Unix с использованием сборки Intel x86 (адрес и значение в операндах памяти)?

Мой код начинается с несколько звонков, которые гласят:

; 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 

Я получаю Segfault. То же самое, если я использую [buf + rlen]. Ни buf, ни ESI сами по себе не являются segfault, поэтому мне кажется, что rlen не делает то, что я думаю.

Любой, кто может помочь мне разобраться, что происходит?

+2

В вашем коде не отображается ввод указателя буфера в 'esi'. Вы уверены, что это то, на что он настроен? И как перемещение «92» добавляет нуль? Если позже в коде вы обрабатываете строку таким образом, который предполагает нулевое завершение, это может зайти за допустимое пространство памяти. – lurker

+0

О, да, плохо. Я использовал обратную косую черту как простой способ увидеть, оказал ли я какое-либо влияние на строку. Что касается ESI, то я снова плохой; строка «mov esi, buf» - это строка, расположенная выше, где я работал. –

ответ

2

Две проблемы с вашим кодом:

mov  byte[esi + rlen], 92 
  • 92 != 0. Конечный нулевой байт, '\0', представляет собой целое число со значением 0.

  • rlen - это адрес, а не значение по этому адресу.

Итак, проверьте, что readed>> 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 

Или, если вы скопировали ECX в регистр, который не затерт система чтения вызова, вы можете использовать это вместо перезагрузки.

Внутри функции подумайте о локальных переменных как о проживании в регистрах и местах памяти только где-нибудь, где вы можете пролить их, если вы запустите низкие регистры. Не будьте похожи на не оптимизирующий компилятор и сохраняйте/перезагружайте свои переменные, когда вам это не нужно. Это проще для архитектуры, такой как x86-64 с 16 рег; 32-битная x86 довольно сильно ограничена и имеет устаревшую версию ABI с атрибутами args-on-the-stack.


Если буфер уже был обнулен, вы могли бы просто передать чтение (2) счетчик, который был один меньше, чем размер буфера. Тем не менее, нулевой только последний байт после чтения возвращается.

+0

Чтобы проверить, понимаю ли я, возвращаемое значение в 'eax' является длиной, правильно? Поэтому, если бы я был склонен использовать «rlen», будет ли он работать над написанием «mov ecx, [rlen]», а затем «add ecx, buf»? То, что я понимаю здесь, это то, что я извлекаю значение, на которое «rlen» указывает, а затем делает его пригодным для использования в моем адресе. –

+0

Да, значение возврата чтения (в eax) - это длина, если она> = 0. ноль означает EOF, отрицательное означает ошибку. Вы не должны загружать '[rlen]' обратно в регистр, это просто глупо. У вас все еще есть значение, которое вы сохранили в eax.Но да, вы можете добавить адрес буфера к счету байтов, как вы описали. Вы также можете написать 'mov [buf + eax], 0' и никогда не загружать адрес buf в регистр вообще. Ключевым моментом является то, что '[buf]' является операндом памяти, 'buf' является непосредственной константой, значением которой является адрес buf. 'buf' не является указателем (это глобальный массив). –

+0

В C мы говорим о 'char buf [1000]', а не 'char * buf'. Обратите внимание, что 'mov esi, buf' является' mov r32, imm32'. Это не загрузка (как при загрузке с адреса). –