Author Topic: First program, segmentation fault (cat, linux)  (Read 27482 times)

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: First program, segmentation fault (cat, linux)
« Reply #15 on: January 18, 2012, 04:01:00 PM »
Wow! Very good! You ask:

Quote
Lets assume the goal was to print up to 4-byte parameters with no spaces...Did I do it in a "suitable" manner?

Well... you print 4 bytes per parameter, not "up to". This is why you're getting an extra character or two when you give parameters of less than four bytes - you really wouldn't want to "clean out" memory. Unlike "printf" or "puts", sys_write doesn't know about zero-terminated strings (which is what we've got), and prints however many characters we tell it in edx. We could get around this "exactly 4 bytes" limitation by 1) linking in the C library and calling "strlen()"... this would really be "overkill" for what we want, or 2) writing our own "strlen" subroutine which returns the length in eax, and doing "mov edx, eax", or 3) writing a custom inline routine which leaves the length in edx where we want it. I like this last method.

This reveals a slight glitch in your program, actually. By not checking for argc=0 until after you've done the sys_write, you actually do sys_write with 0 in ecx the last time. I'm a little surprised that this doesn't segfault, but apparently sys_write checks for it. It will cause a problem in our homemade "strlen"!

As an alternative to counting down argc, we can just keep popping stuff until we find 0 (after this, further up the stack, we find environment variables there's no "count" to them, so we have no choice). Here's my attempt...

Code: [Select]
; nasm -f elf32 myprog.asm
; ld -o myprog myprog.o

global _start

section .data
    newline db 10

section .text
_start:
    pop eax ; argc - ignore it
    pop eax ; program name - ignore it
top:
    pop ecx
    test ecx, ecx ; or cmp ecx, 0
    jz done
    xor edx, edx ; or mov edx, 0
getlen:
    cmp byte [ecx + edx], 0
    jz gotlen
    inc edx
    jmp getlen
gotlen:
; we have ecx and edx set
    mov ebx, 1 ; stdout
    mov eax, 4 ; sys_write
    int 80h
; might want to print a space here, actually...
    jmp top
done:
    mov edx, 1 ; just one byte
    mov ecx, newline
    mov ebx, 1 ; stdout
    mov eax, 4 ; sys_write
    int 80h
exit:
    xor ebx, ebx ; or mov ebx, 0 - claim "no error"
    mov eax, 1 ; sys_exit
    int 80h

I don't know if that's any "more suitable" or not - just a different way of doing it...

Best,
Frank