Сборка x86, вводящая в заблуждение ошибка
Я пытаюсь изучить ассемблер, и у меня есть программа с синтаксисом AT&T для использования с GNU AS, которая, по моему мнению, должна работать. Я получаю эту ошибку с GDB:
Program received signal SIGSEGV, Segmentation fault.
.PROGRAM () at concatenator.s:60
60 call strlen
Current language: auto; currently asm
Код является:
.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
Есть ли что-то, что я действительно сделал неправильно, и какие ресурсы вы бы порекомендовали для изучения ассемблера? (Я прочитал статью по сборке WikiBooks X86 и большую часть Руководства по GAS).
3 ответа
Это:
movl (str1), %esp
вероятно, непосредственная причина вашего крушения. Я никогда не работал с системой x86, в которой аргумент был передан в%esp; Вообще говоря, %esp должен всегда оставаться действительным указателем стека. Во многих системах он должен дополнительно соответствовать некоторой гарантии выравнивания во время инструкции вызова.
Я предполагаю, что вы намереваетесь переместить содержимое памяти str1 в область памяти, на которую указывает% esp, но это не то, что он делает. Вы должны увидеть это, выполнив пошаговое выполнение программы в отладочной инструкции. Это важный навык для написания ассемблера, и он поможет вам самостоятельно найти подобные проблемы.
В дополнение к ответу stephentyrone, я предлагаю вам скомпилировать программу на C, которая вызывает strlen с помощью gcc -S, и наблюдать сгенерированный файл.s для правильного соглашения о вызовах в вашей системе (и, как он сказал, передача значения в %esp не является Я бы ожидал, что в%eax будет передан один аргумент, но это было какое-то время, и я тем временем использовал ABI amd64, поэтому я могу быть смущен).
Довольно обычный, безопасный способ передачи параметра в подпрограмму - поместить значение параметра в стек.
Немного более быстрый способ - переместить значение параметра в регистр: но не, как говорит Стивен, в регистр esp (коды операций push, pop, call и ret предполагают, что esp содержит указатель на стек).