Search code examples
assemblyx86scanfcoredumpgnu-assembler

Why does this AT&T assembly code give a segmentation fault?


This is my first assembly source code, I want to use scanf function but this ELF gives a segmentation fault.

So, I tried to solve using core dump, but I couldn't.

using scanf function

.section .data
 
string: 
.ascii "input yournumber : \0"
 
value: 
.ascii "your value is %d \n\0"

scanf:
.ascii "%d"

.section .text

.globl _start

_start:

movl %esp, %ebp
subl $4, %esp

pushl $string
call printf

leal -4(%ebp), %ebx
pushl %ebx
pushl $scanf
call scanf

pushl -4(%ebp)
pushl $value
call printf

pushl $0
call exit

Solution

  • Instead of looking at just the core-dump, look at how you got there by starting the executable inside gdb. Single-step instructions with si. See the bottom of https://stackoverflow.com/tags/x86/info for more GDB tips.

    You have a ton of bugs which can cause crashes, and some which definitely will.


    You define a scanf symbol, so call scanf jumps there.

    It's in the .data section, so the page might not be executable.

    Or maybe the bytes for "%d" decode to x86 machine code that crashes, given those register values.

    Use a different symbol name like scanf_fmt for the scanf format string. Also don't forget to use .asciz to zero-terminate the implicit-length C string.


    If you statically linked this, or you tried this on MinGW or Cygwin, then libc isn't initialized because you're defining _start instead of main. In a dynamically-linked Linux executable, glibc uses dynamic linker hooks to get its init functions called. Even so, it's not recommended to use libc functions from _start.


    printf or scanf might possibly also crash because the stack is only aligned by 8 bytes, when the ABI allows it to assume 16. The stack is aligned by 16 on entry to _start, but you only do 1 push + 1x sub $4, %esp before printf.

    But most Linux distros don't build 32-bit code with -msse2, so the compiler won't use 16-byte alignment-required loads/stores to copy stuff around. (x86-64 glibc's scanf does crash if called with an under-aligned stack.)

    And you do actually call scanf with an aligned stack; a total offset of 16 from entry to _start, because you don't waste instructions cleaning the stack after printf returns. That's a valid choice, as long as you're aware that you're doing it. (It deserves a comment, and / or you could use mov instead of push for later args to reuse those same stack slots.)

    I'd suggest looking at (optimized) compiler output for a function that does what you want. e.g. on https://godbolt.org/