Простой код сборки не распечатывает вывод - PullRequest
2 голосов
/ 16 декабря 2011

С учетом следующего кода:

    .section    .rodata
str:    .string "Hello World!\n"
input:  .long 2
    ########
    .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    pushl   $str
    call    printf

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

Вывод будет "Hello World!" Теперь я пытаюсь получить номер от пользователя, а затем распечатать его на экране, но это не работает (код компилируется, но я сделал что-то не так). Где моя ошибка?

    .section    .rodata
input:  .long   2
    ########
    .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp
    pushl   %ebx    

    call    scanf  # call scanf to get number from the user
    popl    input  # store the number entered by user in input (variable)
    pushl   input  # push it back into the stack
    call    printf # print input

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

С уважением, Рон

Ответы [ 2 ]

3 голосов
/ 16 декабря 2011

Я не совсем уверен, какой тип ассемблера вы используете, однако я мог заставить ваш код компилироваться с gcc, поэтому я придерживался вашего стиля форматирования (не говоря о синтаксисе AT & T).

В любом случае, вам следует проверить документацию на scanf и понять, что она принимает строку формата и указатели на места в памяти, где хранятся считанные значенияin. Он также возвращает количество успешно прочитанных элементов , а не то, что было прочитано.

Теперь сделайте то же самое и проверьте документацию для printf.Вы увидите, что строка формата необходима для печати вашего номера в удобочитаемой форме.Подходящей строкой формата является "%d\n" для печати числа и новой строки.

Ваш код теперь может выглядеть примерно так (который компилируется и прекрасно работает для меня с помощью gcc):

.section .rodata

input_format:  .string  "%d"
output_format: .string  "%d\n"

.section .bss
input:  .long

.section .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    pushl   $input    # push the ADDRESS of input to have the value stored in it
    pushl   $input_format   # give scanf the ADDRESS of the format string
    call    scanf    # call scanf to get number from the user
    addl    $8, %esp # clean up the stack

    # Note the return value of scanf is passed through eax (same for printf)

    pushl   input    # pass the number to printf BY VALUE
    pushl   $output_format  # pass the ADDRESSS of the output format string to printf
    call    printf   # print input

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

Обратите внимание, что я обычно использовал бы db/dw/dd для выделения памяти в секциях .(ro)data и .bss, а не .string и .long, поэтому, если эта часть сделана слегка неправильно, вы можете просто исправить ее.

Вы также можете использовать пространство стека для хранения числа, однако вы уже объявили input, и я хотел оставить код как можно более похожим на тот, который вы имели.То же самое относится ко всему остальному до и после вещей scanf и printf, я просто оставил это как ваш код.

EDIT: Вот пример использования стека для созданиялокальная переменная, в отличие от переменной, объявленной в сегменте .bss или .data:

.section .rodata

input_format:  .string  "%d"
output_format: .string  "%d\n"

.section .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    subl    $4, %esp       # allocate 4 bytes on the stack for a local variable

    # The local variable will be at -4(%ebp)

    leal    -4(%ebp), %eax # get the ADDRESS of our local variable
    pushl    %eax          # push the ADDRESS of the variable on the stack
    pushl   $input_format  # give scanf the ADDRESS of the format string
    call    scanf          # call scanf to get number from the user
    addl    $8, %esp       # clean up the stack

    # Note the return value of scanf is passed through eax (same for printf)

    pushl   -4(%ebp)       # pass the number to printf BY VALUE
    pushl   $output_format # pass the ADDRESSS of the output format string to printf
    call    printf         # print the input

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret
3 голосов
/ 16 декабря 2011

Ваши аргументы для scanf неверны, вам нужно использовать как формат сканирования, так и буферы для хранения типов, которые вы ищете, затем, если они не являются строками, вам нужно нажмите новую строку форматирования на printf, в этом случае "%d".

это будет выглядеть примерно так (извините, в формате Intel / MASM):

SUB ESP,4 ;make stack space for an int
LEA EAX,[ESP]
PUSH EAX
PUSH offset NumberString ;"%d"
CALL scanf
PUSH [ESP+8] ;our scanned number
PUSH offset NumberString ;"%d"
CALL printf
ADD ESP,14 ;clean up for the cdecl funcs and the alloc'ed stack space
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...