2013-08-02 3 views
1

Я пытаюсь изучить некоторые очень простые ASM, чтобы помочь мне с чтением вывода gdb, выясняющего материал. Я слежу за несколькими учебниками в Интернете и сталкиваюсь с чем-то, что я не могу понять, как это сделать.Stack-based string IO с asm - что я делаю неправильно?

В следующем учебном пособии (http://programminggroundup.blogspot.fr/2007/01/programming-from-ground-up.html) рассказывается о строке IO в главе 5. Он использует сегмент .bss, чтобы объявить массив длиной 500 для ввода. Я могу заставить это работать без проблем. Тем не менее, теперь я пытаюсь получить массив в стеке, а не в сегменте .bss (который для меня похож на «глобальную память»).

Проблема в том, что я не могу понять, что я делаю неправильно. Насколько я могу видеть здесь, я переместил 64-байтовый раздел в стек, который я пытаюсь использовать для хранения ввода, а затем выводю его. Код не является ядром или иным образом не экспонируется, но когда я запускаю его и набираю «Hello» (без кавычек), тогда результат будет «ello», написанный в следующей командной строке. За ним следует возврат линии, поэтому «ello» немедленно выполняется по окончании программы.

[email protected]:~/folderomitted>./basic_io 
Hello 
[email protected]:~/folderomitted>ello 

Насколько я могу видеть здесь, я пишу в стек. Я бы ожидал, что мне не нужно его обнулять, так как вход должен правильно переписывать содержимое. Я что-то здесь безумно ошибаюсь?

Это система unix IA-64 с газом. Кроме того, если я делаю вещи, которые действительно тупые (не только связанные с проблемой, которые у меня есть), скажите, пожалуйста!

.section .text 
.globl _start 
_start: 
    pushq %rbp # Store the original base pointer on the stack 
    mov %rsp, %rbp # The new base pointer is targeting the start of the stack 
    sub $64, %rsp # Move the stack pointer down by 64 bytes, thus saying we have 64 bytes to play with 
    mov %rsp, %rcx # Pass the content of the stack pointer to rcx, for the system call 
    mov $64, %rdx # Store the length of the buffer 
    mov $3, %rax # State that we want to use system_read 
    mov $0, %rbx # Select the handler (STDIN) 
    int $0x80 # invoke 


    mov $4, %rax # system_write 
    mov $1, %rbx # STDOUT 
    mov $64, %rdx # length of buffer 
    mov %rsp, %rcx # location of the buffer on the stack 
    int $0x80 # invoke 

    mov %rbp, %rsp # Restore the stack pointer to the original location 
    popq %rbp # pop the base pointer off the stack 

    mov $1, %rax # sys_exit 
    mov $0, %rbx # return code 
    int $0x80 # invoke 
+2

Поскольку это 64-разрядный код, вы можете переключиться с использования устаревших системных вызовов ('int 0x80') на использование команды' syscall'. Обратите внимание, что регистры, используемые для аргументов, будут отличаться (см. [Эта страница] (http://esec-lab.sogeti.com/post/2011/07/05/Linux-syscall -ABI)), и так будут перечислены столбцы (см. [unistd_64.h] (http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/include/asm-x86/unistd_64.h?v=2.6.25)) , – Michael

ответ

1

Это выглядит как тот же вопрос:

Linux write sys call using string on stack

Отказ от ответственности: Я бег 32-разрядного оборудования и не имею опыта работы с 64-битным кодом. Это может быть ошибкой использовать 32-битную ссылку (отличный PGU от Jon Bartlett!) Для 64-битного кода. Как указано в ссылке выше (и справа), вы используете 32-битные номера системных вызовов, помещая параметры в регистры, подходящие для 32-битного кода, и используя 32-разрядный int 0x80. Мне сказали, что это работает (по-прежнему), и вы подтверждаете, что он работает с буфером в .bss. Я думаю, что %rsp «слишком высок», как указано в ссылке.

В любом случае sys_read не возвращает строку с нулевым символом, а sys_write не обращает на это никакого внимания, если это так. sys_write записывает количество байтов в %edx (%rdx) независимо от того, является ли это «мусором» или нет. sys_read возвращает количество байтов, фактически введенное в %eax (%rax), и это то, что вы хотите поместить в %edx (%rdx) (тот же регистр для 32- или 64-разрядного кода в этом случае) для sys_write. Это не ваша проблема, но она по-прежнему «неправильная».

Я видел эту проблему с «избытком», появляющейся в командной строке, если пользовательский тип пользователя больше, чем разрешен в %edx в 32-битном коде. Это потенциально «опасно»! Вероятно, это хорошая идея «сбросить буфер», если это необходимо. Если %eax (%rax) составляет менее %edx (%rdx), вы в порядке. Если они равны, проверьте последний байт в буфере для перевода строки (код ascii 0xa). Если он там, ты в порядке. Если нет, продолжайте читать, пока не найдете строку перевода. Это, вероятно, «перебор» для игрушечной программы, где вы единственный пользователь, но по-прежнему неплохо было знать об этой проблеме.

+0

Спасибо - я преобразовал его в x86 и собрал/связал в 32-битном режиме, и он отлично работает. На данный момент я буду придерживаться того, что делаю на 32-битной основе, пока я следую учебным пособиям, а затем сделаю переход на 64-битный. –

 Смежные вопросы

  • Нет связанных вопросов^_^