tags:

views:

350

answers:

3

I am trying to learn assembly, and have a program in AT&T syntax, for use with GNU AS Which I believe should work. I receive this error with GDB:

Program received signal SIGSEGV, Segmentation fault.
.PROGRAM () at concatenator.s:60
60              call    strlen
Current language:  auto; currently asm

The code is:

.file "concatenator.s"
.globl _start
.section .text
strlen:
 mov %esp, (str1)
 push %ebx
 push %ecx
 push %edx

        mov $1, %edi
        sub     %ecx, %ecx
        sub     %al, %al
        not     %ecx
        cld
        repne   scasb
        not     %ecx
        dec     %ecx
 mov %ecx, %eax



 pop %edx
 pop %ecx
 pop %ebx
 leave
 ret
write:
 push %eax
 push %ebx
 push %ecx
 push %edx
 mov %eax, %ecx
 mov $4, %eax
 mov $4, %edx
 mov $2, %ebx
 int $0x80
 pop %edx
 pop %ecx
 pop %ebx
 pop %eax
 ret

.globl concatenate
concatenate:
 pop %eax
 mov %eax, (str2)
 pop %eax
 mov %eax, (str1)
 push  %ebx
 push %ecx
 push %edx
        pushl   %ebp#Pushes Previous programs local vars to the stack.
        movl    %esp, %ebp
        subl    $24, %esp
.PROGRAM:
        movl    (str1), %esp#Moves str1 to ESP
 call    strlen#//Strlen counts len of ESP
        movl    %eax, -16(%ebp)#//Moves eax[Return] into ebp[-16](len)
        movl    $str2, (%esp)#//Moves str2 to ESP
        call    strlen#//Counts len of ESP
        subl    $1, %eax#//Removes one from the return value
        movl    %eax, -12(%ebp)#//Stores return in INT len2
        //movl  -12(%ebp), %eax
        movl    %eax, -8(%ebp)#//Stores return in INT J
        movl    $0, -4(%ebp)##//INT X = 0
        jmp     .L7
.L8:
        addl    $1, -8(%ebp)#//ADDS 1 to J
        movl    -8(%ebp), %eax#//Moves J to EAX
        movl    -4(%ebp), %edx#//MOVES X TO EDX
        movzbl  str1(%edx), %edx#//Moves str1[EDX] (EDX is X) to EDX and fills wit null
        movb    %dl, str2(%eax)#//Moves one byte, (Tbhe character we just copied) into str2 [EAX]
        addl    $1, -4(%ebp)#//INT X++
.L7:
        movl    -4(%ebp), %eax#//Moves INT X to EAX
        cmpl    -16(%ebp), %eax#//Compares len with EAX
        jl      .L8#//While below length of string one, go to L8 and copy str1 to str2
        addl    $1, -8(%ebp)#//Adds one to J(J++)
        movl    -8(%ebp), %eax#//Moves J to EAX
        movb    $0, str2(%eax)#//Adds null character to string at position J.
.RETURN:
 leave
        pop %edx
 pop %ecx
 pop %ebx
 mov (str2), %eax
 ret

_start:
push str1
push str2
call concatenate
mov %eax, str2 
mov $1, %eax
mov $0, %ebx
int $0x80


.globl str1
.section .data
str1:
        .string "DEF"
        .zero   252
str2:
        .string "ABC"
        .zero   252

Is there anything I really obviously did wrong?, and which resources would you recommend for learning assembly? (I have read the WikiBooks X86 Assembly Article, and Most of the GAS Manual).

+6  A: 

This:

movl    (str1), %esp

is likely the immediate cause of your crash. I've never worked with a x86 system on which an argument was passed in %esp; generally speaking, %esp must remain a valid stack pointer at all times. On many systems, it must additionally meet some alignment guarantee at the time of a call instruction.

I assume that you intend to move the memory contents of str1 to the memory location pointed to by %esp, but that's not what this does. You should be able to see that by stepping through the program execution in the debugger instruction-by-instruction. This is an important skill to learn for writing assembly, and will help you find issues like this on your own.

Stephen Canon
Thanks, I was attempting to reuse code from GCC, and that was what it had done, need to be more careful next time !
Just to explain why you were seeing a SIGSEGV error, it's because the call pushes the address of the next instruction onto the stack; since you had just loaded some arbitrary data into %esp, it wasn't pointing at a valid stack address, and so the attempt to push the return address (a store to str1, interpreted as a memory location) causes the SIGSEGV.
Stephen Canon
A: 

In addition to stephentyrone's answer, I suggest that you compile a C program that calls strlen with gcc -S and observe the generated .s file for the proper calling convention on your system (and as he said, passing the value in %esp is not it. I would have expected a single argument to be passed in %eax but it's been some time and I have been using the amd64 ABI meanwhile so I may be confused).

Pascal Cuoq
Yes, the two most common calling conventions on x86 in my experience are (a) integer/pointer arguments passed in %eax and %edx and (b) arguments passed on the stack.
Stephen Canon
A: 

A fairly normal, safe way to pass a parameter to a subroutine is to push the parameter value onto the stack.

A slightly quicker way is to move the the parameter value into a register: but not, as stephen says, the esp register (the push, pop, call, and ret opcodes assume that esp contains a pointer to the stack).

ChrisW