Search code examples
linuxassemblyx86printfscanf

How to read input string from keyboard using assembly language


I'm trying to write a simple program that takes string from the keyboard, then prints it to the screen. So far I couldn't make it work.

Here's the code:

    .section .rodata
output: .string "you entered %s\n"
input:  .string "%s"

    .text
.globl  main
    .type   main, @function

main:
    pushl   %ebp
    movl    %esp, %ebp

    subl    $100, %esp
    pushl   $input
    call    scanf

    movl    %ebp, %esp
    subl    $100, %esp
    pushl   $output
    call    printf

    xorl    %eax, %eax
    movl    %ebp, %esp
    popl    %ebp
    ret

When I execute it, the output is you entered (null) for any given input. when I set the offset of subl $100, %esp command (the one before call print) to subl $104, %esp I get you entered %s, and when the offset is set to 108 I get you entered *gibberish*.

I feel like it's a game where I need to guess where scanf saved the string on the stack (why isn't it where it should be?).

I am using IA32 instruction set.

Any help would be greatly appreciated.


Solution

  • Basically there are 3 problems in your program:

    subl    $100, %esp
    pushl   $input
    # Error 1:
    # As Frank Kotler already wrote at this point
    # only $input is stored on the stack; however
    # the address of the buffer must also be on
    # the stack (see Frank Kotler's comment)
    call    scanf
    
    movl    %ebp, %esp
    # Error 2:
    # Now the buffer is below ESP.
    # Because interrupts use the kernel stack they
    # will not overwrite the memory below ESP.
    # However signals will destroy the memory below
    # ESP!!
    #
    # Instead of the lines:
    #   movl    %ebp, %esp
    #   subl    $100, %esp
    #
    # You should use something like this:
    #   add $8, %esp
    # or:
    #   lea -100(%ebp), %esp
    #
    
    subl    $100, %esp
    # Error 3:
    # As for "scanf" the second argument
    # is missing on the stack
    pushl   $output
    call    printf