2013-05-08 59 views
0

我正在完成一個彙編程序,它用給定的替換字符替換字符串中的字符。彙編代碼調用C函數,彙編程序本身在我的.c文件中從main調用。但是,當試圖完成並從彙編程序TO C返回一個最終的int值時,我會得到段錯誤。我的.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 

和我的C文件是:

#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返回到C文件中的int值「r」。這只是一個測試,看看我是否可以將一個int返回到c文件中的r。最終我會返回被替換回r的字符數。但是,我需要弄清楚爲什麼上面的代碼是segfaulting。有任何想法嗎?

回答

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

這是一個很大的錯誤。它將根據堆棧中最低的東西返回,並且您剛剛將某些內容推送到堆棧,這幾乎肯定不是有效的返回地址。

大多數函數通過簡單地將它放入eax(這取決於調用約定,當然這是一個很常見的函數),但通常不需要將它推入堆棧,並且確實有很大的缺點所以。

+0

我明白了。糾正我,如果我錯了,但如果我想從彙編到C返回一個值,我會將它存儲在EAX寄存器中,不是嗎? – user2357446 2013-05-08 08:29:28

+0

不,不是「不」:-)我的意思是,通常你只是把它推入eax並返回。 – paxdiablo 2013-05-08 08:30:14

0

返回值通常存儲在X86 32位機器上的EAX中。所以,你推到堆棧將其存儲在EAX後是錯誤的,因爲它返回到功能將嘗試使用什麼是EAX的值IP(指令指針)

懲戒不帶參數的持久性有機污染物返回地址關閉堆棧並跳轉到它。

source

+0

我明白了,所以我不應該在返回之前將它推入堆棧,而應該簡單地將eax更改爲9,然後返回而不推送它?編輯:剛試過這個,它工作:)。謝謝你。我忘記了(如下面的答案),大多數函數只需將代碼放入eax就可以返回代碼,而無需推送代碼。 – user2357446 2013-05-08 08:30:45

+0

@ user2357446是的,這就是你應該做的:) – 2013-05-08 08:31:25

+0

好吧,現在我唯一的問題是弄清楚如何存儲一個計數器來計算被替換的字符數。我試着簡單地將計數器存儲在bl中,然後在返回之前將bl存儲到[eax]中,但該段錯誤。我假設它是因爲在函數調用 – user2357446 2013-05-08 08:35:02