Search code examples
linuxassemblyx86att

Print counter 0 --> 4 using x86 assembly and at&t on Linux


I'd like to print the counter of a loop (0 --> 4). In the code below diff is the ASCII number of '0' character, max the times the loop repeats, count the counter and p is the variable that contain the character.

.data

.text

.global main

diff    =   48
max     =   5   

count:  .byte   0
p:      .long   0

main:

compare:
    cmpb    $max,count    # if counter is equal or above max
    jae     end           # jump to end

    movl    $4,%eax       # write
    movl    $1,%ebx       # stdout
    xor     %ecx,%ecx     # reset ecx
    addb    $diff,%cl     # add ASCII number of '0'
    addb    count,%cl     # add value of counter
    movb    %cl,p         # move ASCII value of the counter
    movl    $p,%ecx       # move the number to third argument of write
    movl    $4,%edx       # size of long
    int     $0x80         # interrupt

    movb    count,%al     # move value of the counter to al
    inc     %al           # increment al
    movb    %al,count     # move value of al to counter
    jmp     compare       # always jump to compare

end:
    movl    $1,%eax       # exit
    movl    $0,%ebx       # exit(0)
    int     $0x80         # interrupt

It doesn't work. gcc doesn't give me errors, but executing it gives a core dump. Why?


Solution

  • Your variables count and p are defined after the .text directive, which means they are in the text section. This section is supposed to be used for code and is read-only. So attempting to write to these locations causes a segfault.

    You probably wanted to define them following the .data directive.

    After fixing this, it looked like the program works, but actually there is another bug. On each loop iteration you invoke write with 4 bytes, an entire long. The upper bytes are 0. So instead of writing one byte, ascii 0 (0x30), you write 4 bytes (0x30 0x00 0x00 0x00). Your program outputs a total of 20 bytes instead of 5.

    You probably want to just write one byte. In that case you would want to set %edx to 1 when invoking write. And in that case, p can just be a .byte instead of .long.

    By the way, if you run this under a debugger (such as gdb), you will immediately see which instruction faulted. If you didn't do that, you should! Knowing how to use a debugger is essential for a programmer in any language, but most especially assembly.

    If you did, it would have been nice to include the information in your question.