title: Help with Assembly. Segmentation fault when compiling samples on Mac OS X
body: <p>I'm trying to learn assembly using Dr Paul Carter's pcasm book: <a href="http://www.drpaulcarter.com/pcasm/" rel="nofollow noreferrer">http://www.drpaulcarter.com/pcasm/</a></p>
  
  <p>The author doesn't packaged Mac OS X samples, then I've started using from linux sources. Here is the first sample, that uses his library asm_io.</p>
  
  <p>I'm getting Segmentation Fault when running it. Why? What need to be changed to run in mac?</p>
  
  <p>I think if you know asm, maybe you can tell me what's happening.</p>
  
  <p>Here's the sources.</p>
  
  <p>asm_io.asm:</p>
  
  <pre><code>;
  ; 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 = &amp; 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 &amp; 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 -&gt; valid number
   je valid_st
   cmp ax, 1  ; 01 -&gt; zero
   je zero_st
   cmp ax, 2  ; 10 -&gt; invalid number
   je invalid_st
   push edi  ; 11 -&gt; 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
  </code></pre>
  
  <p>asm_io.inc:</p>
  
  <pre><code> 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
  </code></pre>
  
  <p>first.asm</p>
  
  <pre><code>;
  ; 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
  </code></pre>
  
  <p>drive.c:</p>
  
  <pre><code>#include "cdecl.h"
  
  int PRE_CDECL asm_main( void ) POST_CDECL;
  
  int main()
  {
    int ret_status;
    ret_status = asm_main();
    return ret_status;
  }
  </code></pre>
  
  <p>Now I compile it using:</p>
  
  <p>nasm -f macho first.asm</p>
  
  <p>nasm -f macho asm_io.asm</p>
  
  <p>gcc first.o asm_io.o driver.c -o first -arch i386</p>
  
  <p>Then run:
  ./first</p>
  
  <p>Segmentation fault</p>
  
  <p>It happens only when I'm using asm_io lib.</p>
  
  <p>Thank you,</p>
  
  <p>Daniel Koch</p>