2016-07-07 3 views
0

Я учусь, как работать с процедурами masm32 поэтому я написал процедуру, написать номер:SIGSEGV, вина Сегментация при этом «РЭТ»

.386 
.model flat, stdcall 
option casemap : none 

include \masm32\include\masm32.inc 
include \masm32\include\kernel32.inc 
include \masm32\macros\macros.asm 
includelib \masm32\lib\masm32.lib 
includelib \masm32\lib\kernel32.lib 

.data 
    number dw 397 
    temp db 10 
    symbol dw ? 
    i dw ? 

.code 
    printnumber proc num:WORD 
    mov ecx, 0 
    mov ax, num 
    @@: 
    mov edx, 0 
    div temp 
    mov bh, 0 
    mov bl, ah  
    push bx 
    inc cx 
    cmp al, 0 
    mov bl, al 
    mov ax, bx 
    jnz @B 
    mov i, cx 
    @@: 
    pop symbol 
    add symbol, 48 
    mov ax, symbol 
    print ADDR symbol 
    dec i 
    cmp i, 0 
    jnz @B 
    ret 
printnumber endp 

start: 
    push number 
    call printnumber 
    ret ;here program fails 
end start 

печатает программы «397» успешно, но после попытки «ret» возникает проблема: «Программный сигнал SIGSEGV, ошибка сегментации». Что мне делать?

+0

У вас есть неуравновешенный стек. Вы хотите удалить «номер», который вы нажали. – Jester

ответ

0

Вы неуравновешиваете стек, не пытаясь правильно его очистить.

В верхней части файла кода, у вас есть эта директива:

.model flat, stdcall 

Важной частью является stdcall директива, которая определяет соглашение о вызовах, что ваши функции будут использовать. Это наиболее распространенное соглашение о вызовах для программ Windows, и оно является тем же самым, что используется в Windows API. Существуют две важные особенности соглашения о вызове stdcall:

  1. Аргументы помещаются в стек справа налево.
  2. Ответчик несет ответственность за очистку стека до его возвращения.

Первая особенность такая же, как и в других обычных соглашениях о вызовах, cdecl, но вторая точно противоположна. В этом случае вы ошибаетесь. (На самом деле, ваш код вообще не очищает стек, поэтому он будет нарушен независимо от соглашения о вызове!)

В принципе, когда вы используете соглашение о вызове stdcall, вы будете использовать версию ret instruction, которая берет немедленный аргумент. Этот аргумент указывает количество байтов, которые нужно поместить из стека после возврата.

В этом случае, у вас есть один аргумент, WORD размера number, так что вы будете использовать ret 2:

printnumber proc num:WORD 
    mov ecx, 0 
    mov ax, num 
    @@: 
    mov edx, 0 
    div temp 
    mov bh, 0 
    mov bl, ah  
    push bx 
    inc cx 
    cmp al, 0 
    mov bl, al 
    mov ax, bx 
    jnz @B 
    mov i, cx 
    @@: 
    pop symbol 
    add symbol, 48 
    mov ax, symbol 
    print ADDR symbol 
    dec i 
    cmp i, 0 
    jnz @B 
    ret 2   ; clean up the stack by popping 2 bytes, 
        ; since 2 bytes were pushed by the caller 
printnumber endp 

Помимо этого, я верю что с start точку входа masm32 в ярлык, вы должны вызвать ExitProcess, чтобы вернуть управление в Windows. All the MASM32 samples Я видел do it this way:

start: 
    push number 
    call printnumber 
    invoke ExitProcess, 0 
end start 

Но я мог бы быть неправильно об этом. Я фактически не использую MASM32 SDK. Обычно ваша точка входа будет функцией cdecl, которая просто возвращает управление с помощью ret.

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

  • Нет связанных вопросов^_^