2013-05-08 4 views
0

Я заканчиваю программу сборки, которая заменяет символы в строке с заданным символом замены. Код сборки вызывает функции C, а сама программа сборки вызывается из main в моем .c файле. Однако, пытаясь закончить и вернуть окончательное значение int из программы сборки TO C, я получаю segfaults. Мой файл .asm выглядит следующим образом:Сборка Возврат int к функции C segfaults

; File: strrepl.asm 
; Implements a C function with the prototype: 
; 
; int strrepl(char *str, int c, int (* isinsubset) (int c)) ; 
; 
; 
; Result: chars in string are replaced with the replacement character and string is returned. 

    SECTION .text 
    global strrepl 


_strrepl: nop 
strrepl: 
    push ebp   ; set up stack frame 
    mov ebp, esp 

    push esi   ; save registers 
    push ebx 
    xor eax, eax 
    mov ecx, [ebp + 8]  ;load string (char array) into ecx 
    jecxz end   ;jump if [ecx] is zero 
    mov al, [ebp + 12]  ;move the replacement character into esi 
    mov edx, [ebp + 16]  ;move function pointer into edx 

firstLoop: 

    xor eax, eax 

    mov edi, [ecx] 
    cmp edi, 0 
    jz end 

    mov edi, ecx  ; save array 


    movzx eax, byte [ecx]  ;load single byte into eax 
    push eax   ; parameter for (*isinsubset) 
    mov edx, [ebp + 16]   
    call edx   ; execute (*isinsubset) 


    mov ecx, edi  ; restore array 
    cmp eax, 0 
    jne secondLoop 
    add esp, 4   ; "pop off" the parameter 
    mov ebx, eax  ; store return value 
    add ecx, 1 
    jmp firstLoop 

secondLoop: 
    mov eax, [ebp+12] 
    mov [ecx], al 
    mov edx, [ebp+16] 
    add esp, 4 
    mov ebx, eax 
    add ecx, 1 
    jmp  firstLoop 

end: 
    pop ebx   ; restore registers 
    pop esi 
    mov esp, ebp  ; take down stack frame 
    pop ebp 
    mov eax, 9 
    push eax   ;test 
    ret 

и мой файл с:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 

//display *((char *) $edi) 
// These functions will be implemented in assembly: 
// 

int strrepl(char *str, int c, int (* isinsubset) (int c)) ; 


int isvowel (int c) { 

    if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') 
     return 1 ; 

    if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U') 
     return 1 ; 

    return 0 ; 
} 

int main(){ 
    char *str1; 
    int r; 


    str1 = strdup("ABC 123 779 Hello World") ; 
    r = strrepl(str1, '#', &isdigit) ; 
    printf("str1 = \"%s\"\n", str1) ; 
    printf("%d chararcters were replaced\n", r) ; 
    free(str1) ; 
    return 0; 
} 

В моей сборке кода, вы можете увидеть в конце

mov eax, 9 
push eax 

Я просто пытаюсь верните значение 9 в значение «r», которое является int в файле C. Это просто тест, чтобы проверить, могу ли я вернуть int обратно в r в файле c. В конце концов я вернусь к числу символов, которые были заменены на r. Тем не менее, мне нужно выяснить, почему следующий код выше является segfault. Есть идеи?

ответ

0
mov  eax, 9 
push eax   ; NOT a good idea 
ret 

То есть в большой ошибку. Он будет возвращаться на основе самой низкой вещи в стеке, и вы только что подтолкнули что-то к стеку, что почти наверняка не является верным адресом возврата.

Большинство функций возвращают код, просто помещая его в eax (это, конечно, зависит от соглашения о вызове, но это довольно распространенный вопрос), обычно нет необходимости вставлять его в стек и, конечно, так.

+0

я вижу. Исправьте меня, если я ошибаюсь, но если бы я хотел вернуть значение FROM assembly TO c, я бы сохранил его в регистре EAX, нет? – user2357446

+0

Нет, не «нет» :-) Я имею в виду, да, обычно вы просто вставляете его в eax и возвращаетесь. – paxdiablo

0

Возвращаемые значения обычно хранятся в EAX на 32-разрядных машинах X86. Так что ваш толкая его в стеке после хранения в EAX это неправильно, потому что функция это возвращается будет пытаться использовать то, что находится в EAX в качестве значения для IP (указатель инструкций)

Ret без каких-либо аргументов хлопков адрес возврата из стека и переходит к нему.

source

+0

Я вижу, поэтому вместо того, чтобы возвращать его в стек, я должен просто изменить eax на 9, а затем вернуться, не нажимая его? Изменить: просто попробовал это, и это сработало :). Спасибо за это. Я забыл (например, ответ ниже), большинство функций возвращают код, просто помещая его в eax без необходимости его нажимать. – user2357446

+0

@ user2357446 да вот что вам следует делать :) –

+0

Ну, теперь моя единственная проблема - выяснить, как хранить счетчик, чтобы подсчитать количество замененных символов. Я попытался просто сохранить счетчик в bl, а затем сохранить bl в [eax] перед возвратом, но это segfaults. Я предполагаю, потому что где-то в коде bl изменяется между вызовами функций. – user2357446

Смежные вопросы