How to sort signed numbers using assembly language? - sorting

I have this homework wherein I need to make a program that asks three SIGNED numbers from the user and my program should be able to sort these numbers in ascending order. I can do it in C++ but I am not that familiar with NASM/Assembly Language.
Here's my code so far:
%include "asm_io.inc"
segment .data
;
; Output strings
;
prompta db "Enter the 1st number: ", 0
promptb db "Enter the 2nd number: ", 0
promptc db "Enter the 3rd number: ", 0
promptd db "The sorted list is: ", 0
segment .bss
input resd 1
segment .text
global _asm_main
_asm_main:
enter 0,0 ; setup routine
pusha
mov eax, prompta
call print_string
call read_int
push eax
mov eax, promptb
call print_string
call read_int
push eax
mov eax, promptc
call print_string
call read_int
push eax
call add_stack
mov ebx, eax
mov eax, promptd
call print_string
mov eax, ebx
call print_int
call print_nl
sub esp, 16
popa
mov eax, 0 ; return back to C
leave
ret
segment .data
; no need for .data
segment .bss
; no need for variables
segment .text
add_stack:
enter 0,0
mov ecx, [ebp+8]
mov ebx, [ebp+12]
mov eax, [ebp+16]
cmp eax, ebx
jg A
cmp ebx, ecx
jg B
cmp ecx, eax
jg C
A:
push eax
B:
push ebx
C:
push ecx
popa
leave
ret

In C++ you cannot change the arguments inside of a function and use it later by the caller, but in assembly you can do everything. You pushed the input onto the stack for later using as arguments for the function add_stack. What about to sort these values and store them back to the original place on the stack:
%include "asm_io.inc"
segment .data
;
; Output strings
;
prompta db "Enter the 1st number: ", 0
promptb db "Enter the 2nd number: ", 0
promptc db "Enter the 3rd number: ", 0
promptd db "The sorted list is: ", 0
segment .text
global _asm_main
_asm_main:
enter 0,0 ; setup routine
pusha
mov eax, prompta
call print_string
call read_int
push eax
mov eax, promptb
call print_string
call read_int
push eax
mov eax, promptc
call print_string
call read_int
push eax
call sort_stack ; Three arguments pushed before
mov eax, promptd
call print_string
mov ecx, 3 ; Pop and write the arguments for `sort_stack`
.print_list:
pop eax
call print_int
mov al, 32
call print_char
loop .print_list
call print_nl
popa
mov eax, 0 ; return back to C
leave
ret
sort_stack:
enter 0,0
mov ecx, [ebp+8]
mov ebx, [ebp+12]
mov eax, [ebp+16]
cmp eax, ebx
jg .1
xchg eax, ebx
.1:
cmp ebx, ecx
jg .2
xchg ebx, ecx
.2:
cmp eax, ebx
jg .3
xchg eax, ebx
.3: ; Write back the registers
mov [ebp+8], ecx
mov [ebp+12], ebx
mov [ebp+16], eax
leave
ret
I'm not sure, if your teacher will like this "trick".

Related

I'm unsure what the problem with my assembly code it works until eax is popped and replaced by a register

; Input x and y, output min of the two numbers
.586
.MODEL FLAT
INCLUDE io.h
.STACK 4096
.DATA
number DWORD ?
array DWORD 20, 15, 62, 40, 18
nbrElts DWORD 5
prompt BYTE "Enter value:", 0
string BYTE 80 DUP (?)
resultLbl BYTE "Position", 0
result BYTE 11 DUP (?), 0
.CODE
_MainProc PROC
input prompt, string, 20 ; read ASCII characters
atod string ; convert to integer
mov number, eax ; store in memory
push nbrElts ; 3rd parameter (# of elements in array)
lea eax, array ; 2nd parameter (address of array)
push eax
push number ; 1st parameter (value from user)
call searchArray ; searchArray(number, array, 5)
add esp, 12
dtoa result, eax ; convert to ASCII characters
output resultLbl, result ; output label and result
mov eax, 0 ; exit with return code 0
ret
_MainProc ENDP
; searchArray(int x, array, int y)
;
searchArray PROC
push ebp ; save base pointer
mov ebp, esp ; establish stack frame
push eax ; save registers
push ebx
push esi
push ecx
push edx
mov ebx, [ebp+8] ; x, value from user
mov esi, [ebp+12] ; address of array
mov ecx, [ebp+16] ; y, number of elements
mov edx, 1
mov ecx, 5
forLoop:
mov eax, [esi] ; a[i]
cmp eax, ebx ; eax = ebx ?
je isEqual
;cmp eax, ebx
add esi, 4
inc edx
loop forLoop
;mov eax, 0
cmp edx, 6
je notEqual
isEqual:
mov eax, edx
jmp exitCode
notEqual:
mov eax, 0
jmp exitCode
exitCode:
mov eax, edx
pop edx ; restore EBP
pop ecx ; restore EAX
pop esi
pop ebx
pop ebp
ret ; return
searchArray ENDP
END ; end of source code
The pops at the end of the function need to match the pushes at the beginning of the function. If they don't match, the stack pointer ends up in the wrong place and the ret returns to the wrong place.
In your case, you have an extra push without a corresponding pop.
The reason to push registers at the beginning and pop them at the end is to preserve their values. But you don't want to preserve the value of eax. You want to return a different value, the result of the function. So there is absolutely no reason to push eax.

Reading from STDIN and printing to STDOUT with nasm assembly?

As the title suggest I seem to be having a hard time converting the below code to do the exact same thing, which is to read from stdin and stdout. My professor wants us to stop using int 80h and switch over to using gcc. I've had no problems with reading input with the below code however, switching over to gcc is where I start getting segmentation core dump errors.
section .bss
buf resb 1 ; 1000-byte buffer (in data section)
section .text
global _start
_start:
loop1: mov edx, 1 ; max length
mov ecx, buf ; buffer
mov ebx, 0 ; stdin
mov eax, 3 ; sys_read
int 80h
cmp eax, 0 ; end loop if read <= 0
jle lpend1
mov edx, eax ; length
mov ecx, buf ; buffer
mov ebx, 1 ; stdout
mov eax, 4 ; sys_write
int 80h
jmp loop1 ; go back for more
lpend1:
mov eax, 1
mov ebx, 0
int 80h
My attempt at converting the above to perform the same task
SECTION .data
format: db "%c",0
SECTION .bss
buff: resb 1
SECTION .text
extern printf
extern scanf
global main
main:
loop1:
push buff ;buff will hold the characters in the string/file
push format ;expect character for every buff
call scanf
add esp, 8 ;clear stack
cmp eax, 0 ;if eax is equal to 0 then EOF
je lpend1 ;jump to end main func
xor eax, eax ;clear eax
mov eax, buff ;mov buff to eax register
push eax ;push eax onto the stack
mov eax, format ;mov the string format to eax
push eax ;push onto the stack
call printf ;call printf, prints to screen
add esp, 8 ;clear the stack
jmp loop1 ;jump back to top and repeat
lpend1:
ret ;end of main

Insertion sort in assembler doesn't sort

I'm trying to sort a array of numbers by Insertion sort but it not sort the numbers correctly. I've tried everything but it does not sort them As it should.
I would be happy if you could help me figure out where the problem and on how I can fix it thanks !!
section .rodata
MSG: DB "welcome to sortMe, please sort me",10,0
S1: DB "%d",10,0 ; 10 = '\n' , 0 = '\0'
section .data
array DB 5,1,7,3,4,9,12,8,10,2,6,11 ; unsorted array
len DB 12
section .text
align 16
global main
extern printf
main:
push MSG ; print welcome message
call printf
add esp,4 ; clean the stack
call printArray ;print the unsorted array
push ebp ;save old frame pointer
mov ebp,esp ;create new frame on stack
pusha
mov esi,array
mov ecx,8
OuterLoop:
mov ebx,ecx
InnerLoop:
add esi,ebx ;basically makes array[0] to array[ebx]
mov eax,[esi] ;eax=array[ebx]
sub esi,8
mov edx,[esi] ; edx=array[ebx-1]
add esi,8
cmp eax,edx ; if(eax<edx)
jle skip2 ; skip the loop
;else:
mov [esi],edx ;array[ebx]=array[ebx-1]
sub esi,8
mov [esi],eax ; array[ebx-1]=array[ebx]
add esi,8
sub esi,ebx ; return the array to its original state (array[0])
sub ebx,8
cmp ebx,0
jne InnerLoop
skip1:
add ecx,8
cmp ecx,96
jle OuterLoop
popa ;restore registers
mov esp,ebp ;clean the stack frame
pop ebp
push MSG ; print welcome message (to divide between the unsorted and sorted)
call printf
add esp,4 ; clean the stack
call printArray
mov eax, 1 ;exit system call
int 0x80
printArray:
push ebp ;save old frame pointer
mov ebp,esp ;create new frame on stack
pusha ;save registers
mov eax,0
mov ebx,0
mov edi,0
mov esi,0 ;array index
mov bl,byte[len]
add edi,ebx ; edi = array size
print_loop:
cmp esi,edi
je print_end
mov al ,byte[array+esi] ;set num to print in eax
push eax
push S1
call printf
add esp,8 ;clean the stack
inc esi
jmp print_loop
print_end:
popa ;restore registers
mov esp,ebp ;clean the stack frame
pop ebp ;return to old stack frame
ret
skip2:
sub esi,ebx ; return the array to the original state
jmp skip1
You're horribly mixing 3 sizes!
1. Array of bytes
2. Values of dwords
3. Steps of qwords
Once you've decided what size to use beware of this code. In its current qword form it does an extra iteration! (use jl OuterLoop)
cmp ecx,96
jle OuterLoop
Why don't you use MOVZX to EAX in this line? It's much cleaner.
mov al ,byte[array+esi] ;set num to print in eax
The same applies to
mov bl,byte[len]
By putting mov esi,array right after OuterLoop: you can avoid that ugly detour via SKIP2.

Unhandled exception at 0x00000005 in : 0xC0000005: Access violation reading location 0x00000005. when making a ret call

My program is supposed to read an integer n from the user and then calculate all the divisors and if they are prime or not. I am using the Irvine 32 library. Now this is the weird part, when I enter in an even number my program executes as it is supposed to. When I enter in and odd number my program gets the error which is the title of this post.
My main Proc:
main PROC
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block displays greeting and newline;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov edx, OFFSET greeting
call Writestring
call Crlf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block gets the integer from the user;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call GetInt
call Crlf
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block gets calculates the divsiors and prime divisors.;
; It then puts them in to an array to get ready to display. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call CalcDivisors
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This block displays the results to the screen. ;
; in an n-1 by 3 table. ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
call Display_Results
exit
main ENDP
Now the Proc that has produces the error:
CalcDivisors PROC uses eax ebx ecx edx esi edi
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function calculates divisors then pushes them on to an array;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax,0
mov ecx,0
mov ebx,0
mov edx,0
mov esi,0
mov edi,0
mov ecx,n
sub ecx,1
mov eax,n
mov ebx,divisors
mov esi,OFFSET prime_arr
mov edi,OFFSET div_arr
push eax
Calc_Div:
call dumpregs
div ebx
call dumpregs
cmp edx,0
jz Calc_Prime_Div
inc ebx
mov edx,0
mov eax,n
loop Calc_Div
Calc_Prime_Div:
cmp ebx,2
jz Push_2_array
push ebx
push ecx
mov eax,0
mov eax,ebx
mov ecx,ebx
mov divisor_counter,ebx
sub ecx,2
mov ebx,0
mov ebx,prime_divisors
P1:
call dumpregs
div ebx
call dumpregs
cmp edx,0
jz Push_div_array
inc ebx
mov eax,divisor_counter
mov edx,0
loop P1
jmp Push_prime_array
Jump_above:
call dumpregs
loop Calc_div
call dumpregs
jmp foo
Push_prime_array:
pop ecx
pop ebx
mov [esi],ebx
mov eax,[esi]
call writedec
add esi,4
mov eax,0
mov eax,n
call dumpregs
inc ebx
call dumpregs
jmp jump_above
call dumpregs
Push_div_array:
pop ecx
pop ebx
mov [edi],ebx
mov eax,[edi]
call writedec
add edi,4
mov eax,0
mov eax,n
call dumpregs
inc ebx
jmp Jump_above
Push_2_array:
mov [esi],ebx
add esi,4
inc ebx
pop eax
jmp Jump_above
foo:
ret
CalcDivisors ENDP
Now the line that is giving me the exact error is the following:
foo:
ret
It is boggling my mind as to why it is crashing when I enter in an odd number for n and not crashing when n is even. Any suggestions?
It looks like you forget to pop some values from the stack. Check the number of push and pop instructions executed.

Help with Assembly. Segmentation fault when compiling samples on Mac OS X

I'm trying to learn assembly using Dr Paul Carter's pcasm book: http://www.drpaulcarter.com/pcasm/
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.
I'm getting Segmentation Fault when running it. Why? What need to be changed to run in mac?
I think if you know asm, maybe you can tell me what's happening.
Here's the 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;
}
Now I compile it using:
nasm -f macho first.asm
nasm -f macho asm_io.asm
gcc first.o asm_io.o driver.c -o first -arch i386
Then run:
./first
Segmentation fault
It happens only when I'm using asm_io lib.
Thank you,
Daniel Koch
You seem to be using 32-bit assembly code here. One big difference among 32-bit Mac OS X and 32-bit Windows or Linux is that Mac requires the stack to be 16-byte aligned whenever you CALL a function. In other words, at the point in your code where you have a CALL instruction, it is required that ESP = #######0h.
The following may be interesting reads:
http://blogs.embarcadero.com/eboling/2009/05/20/5607
www.agner.org/optimize/calling_conventions.pdf

Resources