2009-12-16 13 views
1

Je suis en train d'apprendre ensemble à l'aide du livre de pcasm Dr Paul Carter: http://www.drpaulcarter.com/pcasm/Aide à l'assemblage. Segmentation fault lors de la compilation des échantillons sous Mac OS X

L'auteur n'a pas emballé échantillons Mac OS X, alors j'ai commencé à utiliser des sources de Linux . Voici le premier exemple, qui utilise sa bibliothèque asm_io.

Je reçois une erreur de segmentation lors de son exécution. Pourquoi? Qu'est-ce qui doit être changé pour fonctionner dans mac?

Je pense que si vous connaissez asm, peut-être que vous pouvez me dire ce qui se passe.

Voici les sources.

asm_io.asm:

; 
; file: asm_io.asm 
; Assembly I/O routines 
; To assemble for DJGPP 
; nasm -f coff -d COFF_TYPE asm_io.asm 
; To assemble for Borland C++ 5.x 
; nasm -f obj -d OBJ_TYPE asm_io.asm 
; To assemble for Microsoft Visual Studio 
; nasm -f win32 -d COFF_TYPE asm_io.asm 
; To assemble for Linux 
; nasm -f elf -d ELF_TYPE asm_io.asm 
; To assemble for Watcom 
; nasm -f obj -d OBJ_TYPE -d WATCOM asm_io.asm 
; IMPORTANT NOTES FOR WATCOM 
; The Watcom compiler's C library does not use the 
; standard C calling convention. For example, the 
; putchar() function gets its argument from the 
; the value of EAX, not the stack. 


%define NL 10 
%define CF_MASK 00000001h 
%define PF_MASK 00000004h 
%define AF_MASK 00000010h 
%define ZF_MASK 00000040h 
%define SF_MASK 00000080h 
%define DF_MASK 00000400h 
%define OF_MASK 00000800h 


; 
; Linux C doesn't put underscores on labels 
; 
%ifdef ELF_TYPE 
    %define _scanf scanf 
    %define _printf printf 
    %define _getchar getchar 
    %define _putchar putchar 
%endif 

; 
; Watcom puts underscores at end of label 
; 
%ifdef WATCOM 
    %define _scanf scanf_ 
    %define _printf printf_ 
    %define _getchar getchar_ 
    %define _putchar putchar_ 
%endif 

%ifdef OBJ_TYPE 
segment .data public align=4 class=data use32 
%else 
segment .data 
%endif 

int_format  db "%i", 0 
string_format  db "%s", 0 
reg_format  db "Register Dump # %d", NL 
     db "EAX = %.8X EBX = %.8X ECX = %.8X EDX = %.8X", NL 
        db "ESI = %.8X EDI = %.8X EBP = %.8X ESP = %.8X", NL 
        db "EIP = %.8X FLAGS = %.4X %s %s %s %s %s %s %s", NL 
      db 0 
carry_flag  db "CF", 0 
zero_flag  db "ZF", 0 
sign_flag  db "SF", 0 
parity_flag  db "PF", 0 
overflow_flag  db "OF", 0 
dir_flag  db "DF", 0 
aux_carry_flag  db "AF", 0 
unset_flag  db " ", 0 
mem_format1   db "Memory Dump # %d Address = %.8X", NL, 0 
mem_format2   db "%.8X ", 0 
mem_format3   db "%.2X ", 0 
stack_format  db "Stack Dump # %d", NL 
      db "EBP = %.8X ESP = %.8X", NL, 0 
stack_line_format db "%+4d %.8X %.8X", NL, 0 
math_format1  db "Math Coprocessor Dump # %d Control Word = %.4X" 
        db " Status Word = %.4X", NL, 0 
valid_st_format  db "ST%d: %.10g", NL, 0 
invalid_st_format db "ST%d: Invalid ST", NL, 0 
empty_st_format  db "ST%d: Empty", NL, 0 

; 
; code is put in the _TEXT segment 
; 
%ifdef OBJ_TYPE 
segment text public align=1 class=code use32 
%else 
segment .text 
%endif 
global read_int, print_int, print_string, read_char 
global print_char, print_nl, sub_dump_regs, sub_dump_mem 
     global sub_dump_math, sub_dump_stack 
     extern _scanf, _printf, _getchar, _putchar 

read_int: 
enter 4,0 
pusha 
pushf 

lea eax, [ebp-4] 
push eax 
push dword int_format 
call _scanf 
pop ecx 
pop ecx 

popf 
popa 
mov eax, [ebp-4] 
leave 
ret 

print_int: 
enter 0,0 
pusha 
pushf 

push eax 
push dword int_format 
call _printf 
pop ecx 
pop ecx 

popf 
popa 
leave 
ret 

print_string: 
enter 0,0 
pusha 
pushf 

push eax 
push dword string_format 
call _printf 
pop ecx 
pop ecx 

popf 
popa 
leave 
ret 

read_char: 
enter 4,0 
pusha 
pushf 

call _getchar 
mov [ebp-4], eax 

popf 
popa 
mov eax, [ebp-4] 
leave 
ret 

print_char: 
enter 0,0 
pusha 
pushf 

%ifndef WATCOM 
push eax 
%endif 
call _putchar 
%ifndef WATCOM 
pop ecx 
%endif 

popf 
popa 
leave 
ret 


print_nl: 
enter 0,0 
pusha 
pushf 

%ifdef WATCOM 
mov eax, 10 ; WATCOM doesn't use the stack here 
%else 
push dword 10 ; 10 == ASCII code for \n 
%endif 
call _putchar 
%ifndef WATCOM 
pop ecx 
%endif 
popf 
popa 
leave 
ret 


sub_dump_regs: 
enter 4,0 
pusha 
pushf 
mov  eax, [esp]  ; read FLAGS back off stack 
mov [ebp-4], eax ; save flags 

; 
; show which FLAGS are set 
; 
test eax, CF_MASK 
jz cf_off 
mov eax, carry_flag 
jmp short push_cf 
cf_off: 
mov eax, unset_flag 
push_cf: 
push eax 

test dword [ebp-4], PF_MASK 
jz pf_off 
mov eax, parity_flag 
jmp short push_pf 
pf_off: 
mov eax, unset_flag 
push_pf: 
push eax 

test dword [ebp-4], AF_MASK 
jz af_off 
mov eax, aux_carry_flag 
jmp short push_af 
af_off: 
mov eax, unset_flag 
push_af: 
push eax 

test dword [ebp-4], ZF_MASK 
jz zf_off 
mov eax, zero_flag 
jmp short push_zf 
zf_off: 
mov eax, unset_flag 
push_zf: 
push eax 

test dword [ebp-4], SF_MASK 
jz sf_off 
mov eax, sign_flag 
jmp short push_sf 
sf_off: 
mov eax, unset_flag 
push_sf: 
push eax 

test dword [ebp-4], DF_MASK 
jz df_off 
mov eax, dir_flag 
jmp short push_df 
df_off: 
mov eax, unset_flag 
push_df: 
push eax 

test dword [ebp-4], OF_MASK 
jz of_off 
mov eax, overflow_flag 
jmp short push_of 
of_off: 
mov eax, unset_flag 
push_of: 
push eax 

push dword [ebp-4] ; FLAGS 
mov eax, [ebp+4] 
sub eax, 10   ; EIP on stack is 10 bytes ahead of orig 
push eax    ; EIP 
lea  eax, [ebp+12] 
push eax    ; original ESP 
push dword [ebp]  ; original EBP 
     push edi 
     push esi 
push edx 
push ecx 
push ebx 
push dword [ebp-8] ; original EAX 
push dword [ebp+8] ; # of dump 
push dword reg_format 
call _printf 
add esp, 76 
popf 
popa 
leave 
ret  4 

sub_dump_stack: 
enter 0,0 
pusha 
pushf 

lea  eax, [ebp+20] 
push eax    ; original ESP 
push dword [ebp]  ; original EBP 
push dword [ebp+8] ; # of dump 
push dword stack_format 
call _printf 
add esp, 16 

mov ebx, [ebp] ; ebx = original ebp 
mov eax, [ebp+16] ; eax = # dwords above ebp 
shl eax, 2   ; eax *= 4 
add ebx, eax ; ebx = & highest dword in stack to display 
mov edx, [ebp+16] 
mov ecx, edx 
add ecx, [ebp+12] 
inc ecx ; ecx = # of dwords to display 

stack_line_loop: 
push edx 
push ecx ; save ecx & edx 

push dword [ebx] ; value on stack 
push ebx ; address of value on stack 
mov eax, edx 
sal eax, 2 ; eax = 4*edx 
push eax ; offset from ebp 
push dword stack_line_format 
call _printf 
add esp, 16 

pop ecx 
pop edx 

sub ebx, 4 
dec edx 
loop stack_line_loop 

popf 
popa 
leave 
ret  12 


sub_dump_mem: 
enter 0,0 
pusha 
pushf 

push dword [ebp+12] 
push dword [ebp+16] 
push dword mem_format1 
call _printf 
add esp, 12 
mov esi, [ebp+12]  ; address 
and esi, 0FFFFFFF0h ; move to start of paragraph 
mov ecx, [ebp+8] 
inc ecx 
mem_outer_loop: 
push ecx 
push esi 
push dword mem_format2 
call _printf 
add esp, 8 

xor ebx, ebx 
mem_hex_loop: 
xor eax, eax 
mov al, [esi + ebx] 
push eax 
push dword mem_format3 
call _printf 
add esp, 8 
inc ebx 
cmp ebx, 16 
jl mem_hex_loop 

mov eax, '"' 
call print_char 
xor ebx, ebx 
mem_char_loop: 
xor eax, eax 
mov al, [esi+ebx] 
cmp al, 32 
jl non_printable 
cmp al, 126 
jg non_printable 
jmp short mem_char_loop_continue 
non_printable: 
mov eax, '?' 
mem_char_loop_continue: 
call print_char 

inc ebx 
cmp ebx, 16 
jl mem_char_loop 

mov eax, '"' 
call print_char 
call print_nl 

add esi, 16 
pop ecx 
loop mem_outer_loop 

popf 
popa 
leave 
ret 12 

; function sub_dump_math 
; prints out state of math coprocessor without modifying the coprocessor 
; or regular processor state 
; Parameters: 
; dump number - dword at [ebp+8] 
; Local variables: 
; ebp-108 start of fsave buffer 
; ebp-116 temp double 
; Notes: This procedure uses the Pascal convention. 
; fsave buffer structure: 
; ebp-108 control word 
; ebp-104 status word 
; ebp-100 tag word 
; ebp-80 ST0 
; ebp-70 ST1 
; ebp-60 ST2 ... 
; ebp-10 ST7 
; 
sub_dump_math: 
enter 116,0 
pusha 
pushf 

fsave [ebp-108] ; save coprocessor state to memory 
mov eax, [ebp-104] ; status word 
and eax, 0FFFFh 
push eax 
mov eax, [ebp-108] ; control word 
and eax, 0FFFFh 
push eax 
push dword [ebp+8] 
push dword math_format1 
call _printf 
add esp, 16 
; 
; rotate tag word so that tags in same order as numbers are 
; in the stack 
; 
mov cx, [ebp-104] ; ax = status word 
shr cx, 11 
and cx, 7   ; cl = physical state of number on stack top 
mov bx, [ebp-100] ; bx = tag word 
shl  cl,1 ; cl *= 2 
ror bx, cl ; move top of stack tag to lowest bits 

mov edi, 0 ; edi = stack number of number 
lea esi, [ebp-80] ; esi = address of ST0 
mov ecx, 8   ; ecx = loop counter 
tag_loop: 
push ecx 
mov ax, 3 
and ax, bx ; ax = current tag 
or ax, ax ; 00 -> valid number 
je valid_st 
cmp ax, 1 ; 01 -> zero 
je zero_st 
cmp ax, 2 ; 10 -> invalid number 
je invalid_st 
push edi ; 11 -> empty 
push dword empty_st_format 
call _printf 
add esp, 8 
jmp short cont_tag_loop 
zero_st: 
fldz 
jmp short print_real 
valid_st: 
fld tword [esi] 
print_real: 
fstp qword [ebp-116] 
push dword [ebp-112] 
push dword [ebp-116] 
push edi 
push dword valid_st_format 
call _printf 
add esp, 16 
jmp short cont_tag_loop 
invalid_st: 
push edi 
push dword invalid_st_format 
call _printf 
add esp, 8 
cont_tag_loop: 
ror bx, 2 ; mov next tag into lowest bits 
inc edi 
add esi, 10   ; mov to next number on stack 
pop ecx 
loop tag_loop 

frstor [ebp-108]  ; restore coprocessor state 
popf 
popa 
leave 
ret 4 

asm_io.inc:

extern read_int, print_int, print_string 
extern read_char, print_char, print_nl 
extern sub_dump_regs, sub_dump_mem, sub_dump_math, sub_dump_stack 

%macro dump_regs 1 
push dword %1 
call sub_dump_regs 
%endmacro 


; 
; usage: dump_mem label, start-address, # paragraphs 
%macro dump_mem 3 
push dword %1 
push dword %2 
push dword %3 
call sub_dump_mem 
%endmacro 

%macro dump_math 1 
push dword %1 
call sub_dump_math 
%endmacro 

%macro dump_stack 3 
push dword %3 
     push  dword %2 
push dword %1 
     call  sub_dump_stack 
%endmacro 

first.asm

; 
; file: first.asm 
; First assembly program. This program asks for two integers as 
; input and prints out their sum. 
; 
; To create executable: 
; Using djgpp: 
; nasm -f coff first.asm 
; gcc -o first first.o driver.c asm_io.o 
; 
; Using Linux and gcc: 
; nasm -f elf first.asm 
; gcc -o first first.o driver.c asm_io.o 
; 
; Using Borland C/C++ 
; nasm -f obj first.asm 
; bcc32 first.obj driver.c asm_io.obj 
; 
; Using MS C/C++ 
; nasm -f win32 first.asm 
; cl first.obj driver.c asm_io.obj 
; 
; Using Open Watcom 
; nasm -f obj first.asm 
; wcl386 first.obj driver.c asm_io.obj 

%include "asm_io.inc" 
; 
; initialized data is put in the .data segment 
; 
segment .data 
; 
; These labels refer to strings used for output 
; 
prompt1 db "Enter a number: ", 0  ; don't forget nul terminator 
prompt2 db "Enter another number: ", 0 
outmsg1 db "You entered ", 0 
outmsg2 db " and ", 0 
outmsg3 db ", the sum of these is ", 0 


; 
; uninitialized data is put in the .bss segment 
; 
segment .bss 
; 
; These labels refer to double words used to store the inputs 
; 
input1 resd 1 
input2 resd 1 



; 
; code is put in the .text segment 
; 
segment .text 
     global _asm_main 
_asm_main: 
     enter 0,0    ; setup routine 
     pusha 

     mov  eax, prompt1  ; print out prompt 
     call print_string 

     call read_int   ; read integer 
     mov  [input1], eax  ; store into input1 

     mov  eax, prompt2  ; print out prompt 
     call print_string 

     call read_int   ; read integer 
     mov  [input2], eax  ; store into input2 

     mov  eax, [input1]  ; eax = dword at input1 
     add  eax, [input2]  ; eax += dword at input2 
     mov  ebx, eax   ; ebx = eax 
     dump_regs 1    ; dump out register values 
     dump_mem 2, outmsg1, 1 ; dump out memory 
; 
; next print out result message as series of steps 
; 
     mov  eax, outmsg1 
     call print_string  ; print out first message 
     mov  eax, [input1]  
     call print_int   ; print out input1 
     mov  eax, outmsg2 
     call print_string  ; print out second message 
     mov  eax, [input2] 
     call print_int   ; print out input2 
     mov  eax, outmsg3 
     call print_string  ; print out third message 
     mov  eax, ebx 
     call print_int   ; print out sum (ebx) 
     call print_nl   ; print new-line 

     popa 
     mov  eax, 0   ; return back to C 
     leave      
     ret 

drive.c:

#include "cdecl.h" 

int PRE_CDECL asm_main(void) POST_CDECL; 

int main() 
{ 
    int ret_status; 
    ret_status = asm_main(); 
    return ret_status; 
} 

Maintenant, je compilez à l'aide:

nasm -f macho first.asm

nasm -f macho asm_io.asm

gcc first.o asm_io.o driver.c -o premier -arch i386

Lancez ensuite: ./first

Segmentation fault

Il ne se produit que lorsque j'utilise asm_io lib.

Merci,

Daniel Koch

+0

est ici la sortie de gdb: $ gdb premier (gdb) run. Démarrage du programme:/Users/daniel/Desktop/linux-ex/first. Lecture de symboles pour les bibliothèques partagées +. done Signal reçu du programme EXC_BAD_ACCESS, Impossible d'accéder à la mémoire. Raison: 13 à l'adresse: 0x00000000 0x91f846d0 dans misaligned_stack_error_() –

Répondre

4

Vous semblez être en utilisant le code assembleur 32 bits ici. Une grande différence entre Mac OS X 32 bits et Windows 32 bits ou Linux est que Mac nécessite que la pile soit alignée sur 16 octets chaque fois que vous avez une fonction. En d'autres termes, au point dans votre code où vous avez une instruction CALL, il est nécessaire que ESP = #######0h.

Ce qui suit peut être intéressant se lit comme suit:

http://blogs.embarcadero.com/eboling/2009/05/20/5607

www.agner.org/optimize/calling_conventions.pdf

+0

Ok, je vais essayer de changer la bibliothèque. Merci beaucoup! :) –

+0

Daniel, as-tu pu modifier les bibliothèques du Dr Paul Carter pour qu'elles travaillent sur osx? Si vous pouviez le poster, ou le lui rendre, ce serait grandement apprécié. Je vous remercie! – dtudury

+0

PhiS, vous êtes un sauveteur. Après 16 octets alignant ma pile tout fonctionne comme un charme. Aussi pour plus de référence - cela a fonctionné pour moi sous OS X en utilisant NASM avec la syntaxe intel et la construction pour x64. – Arqu