Author Topic: how to compare between two value stored in the register and get the bigger one?  (Read 28342 times)

Offline new_geek

  • Jr. Member
  • *
  • Posts: 11
  • Country: 00
Hi everyone, I am a student of computer science. and I'm taking computer organization and embedded systems. and through googling I got partial code, from that I know how to compare the value between two register (jg, jl, je). But the thing that I want to know, is there a specific code so that we know which value is bigger without having to execute jump (loop)?

P.S: let's say, there is a case we need to compare four or five different value and store the biggest among them in R0 and the smallest in R1.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
As a general rule, I think you'll find that assembly language involves writing a large number of simple instructions to do anything. If you've got several values, you're going to have to compare them one at a time to find the largest/smallest. If you've got a more specific question, maybe we can help you with it...

Best,
Frank


Offline new_geek

  • Jr. Member
  • *
  • Posts: 11
  • Country: 00
honestly, its part of school project. so in that project we were given four variables, and we supposed to compare each and every one of them. and then we must store the result in ax and dx. the first register is the largest while the other is the smallest.
Quote
Code: [Select]
section .data
VAR1:
dw 30000
VAR2:
dw 0ABCDH
VAR3:
dw 7FFFH
VAR4:
dw 100010001000B

section .bss

section .text
global _start

_start:
nop

; TODO: your code here

mov ax,0
mov ax, [VAR1]

mov bx,0
mov bx, [VAR2]

mov dx,0
mov dx, [VAR1]

;VAR1 dw 30000
;VAR2 dw 0ABCDH
;VAR3 dw 7FFFH
;VAR4 dw 100010001000b
firstCompare:
cmp bx,ax
jg bxBigger ;condition_new_value_bigger
cmp dx,bx
jl dxSmaller ;condition_new_value_smaller

dxSmaller:
mov dx,[bx]
jmp hereComesVar3

bxBigger:
cmp ax,dx
jne secondCompare

resultBigger:
mov dx,ax
mov ax,[bx]
jmp hereComesVar3

secondCompare:
cmp ax, dx
jg resultBigger

hereComesVar3:
cmp bx,[VAR3]
jne Var3ComesIn
jmp hereComesVar4

Var3ComesIn:
mov bx,[VAR3]
jmp firstCompare

hereComesVar4:
cmp bx,[VAR4]
jne Var4ComesIn
jmp done

Var4ComesIn:
mov bx,[VAR4]
jmp firstCompare
done:
mov ebx, 0
int 0x80

the problem is, every time I want to compile it, it always says segmentation fault.
« Last Edit: October 27, 2013, 11:21:51 PM by new_geek »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Well...
Code: [Select]
mov dx, [bx]
is what's causing the segmentation fault. You're trying to load dx with the "[contents]" of memory at the address in bx. bx, at this point, holds 0ABCDh which is not valid memory - no 16-bit value would be (in a Linux program). You just want to move the value in bx to dx:
Code: [Select]
mov dx, bx

There are similar errors in other places, I just picked on that one. I may have other suggestions... later. Falling asleep right now... :)

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
the problem is, every time I want to compile it, it always says segmentation fault.

I started playing around with your code and noticed a few small problems, unfortunately, once I fixed those problems the code ended up in an infinite loop. This is because registers were getting overwritten during phase 4 of your algorithm. I decided it'd be easier to provide you with an alternative (but similar) solution. I hope the comments are enough to help you follow along. This code leaves lots of room for improvement.

Code: [Select]
section .data
VAR1:
dw 30000
VAR2:
dw 0ABCDH
VAR3:
dw 7FFFH
VAR4:
dw 100010001000B

section .bss

section .text
global _start

_start:
nop

; TODO: your code here


;; Clear the registers we will be using.
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0

;; Move our 16-bit data into our registers.
mov ax, [VAR1]
mov bx, [VAR2]

cmp ax, bx ; Compare AX and BX
jl axSmaller ; If AX < BX Then Goto axSmaller
jg axBigger ; If AX > BX Then Goto axBigger

;; AX and BX are the same, so we AX to both AX and DX.
mov dx, ax ; If AX = BX Then DX := AX
jmp nextTestVar3

axSmaller:
;; AX is smaller so:
mov dx, ax ; DX := AX
mov ax, bx ; AX := BX
jmp nextTestVar3

axBigger:
;; AX is bigger so:
; AX := AX (do nothing)
mov dx, bx ; DX := BX

nextTestVar3:

;; Okay, at this point AX contains the largest of VAR1/VAR2 and DX contains the smallest.
;; We need to test the next variables to see if they will overwrite the current values.

mov cx, [VAR3]

cmp cx, ax ; Compare CX and AX
jg cxBigger ; If CX > AX Then Goto cxBigger

cmp cx, dx ; Compare CX and DX
jl cxSmaller ; If CX < DX Then Goto cxSmaller

;; If we reach this instruction, that means CX was
;; neither greater than AX nor smaller than DX, so we
;; just move on to the next variable.

jmp nextTestVar4

cxSmaller:
;; CX is smaller so:
; AX := AX (do nothing)
mov dx, cx ; DX := CX
jmp nextTestVar4

cxBigger:
;; CX is bigger so:
mov ax, cx ; AX := CX
; DX := DX (do nothing)

nextTestVar4:
;; And we now we repeat the processess with VAR4

mov bx, [VAR4]

cmp bx, ax ; Compare BX and AX
jg bxBigger ; If BX > AX Then Goto bxBigger

cmp bx, dx ; Compare BX and DX
jl bxSmaller ; If BX < DX Then Goto bxSmaller

;; If we reach this instruction, that means BX was
;; neither greater than AX nor smaller than DX, so we
;; are done.

jmp done

bxSmaller:
;; BX is smaller so:
; AX := AX (do nothing)
mov dx, bx ; DX := BX
jmp done

bxBigger:
;; BX is bigger so:
mov ax, bx ; AX := BX
; DX := DX (do nothing)

done:
;; AX = Largest, DX = Smallest


;; CHANGED: EAX contains the system call number (SYS_exit = 1) and
;; EBX contains the error code (EXIT_SUCCESS = 0).
mov ebx, 0
mov eax, 1
int 0x80

Regards,
Bryant Keller

About Bryant Keller
bkeller@about.me

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Nice catch on the missing system call number for "exit"! That would cause a segfault too. I missed that, just glancing over it.

Do we need to discuss the difference between "signed" and "unsigned" numbers? By design or by chance, we're doing signed - "jl" and "jg" are for signed numbers, "jb" and "ja" are for unsigned. Since we're doing signed numbers, VAR2 is going to be smallest (since it will be treated as a negative number) and VAR3 will be largest (it is the largest possible signed 16-bit number). If we were doing unsigned, VAR2 would be largest. You may want to explore the difference...

Again, I'm going to have to leave this for "Later"...

Best,
Frank


Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
Do we need to discuss the difference between "signed" and "unsigned" numbers? By design or by chance, we're doing signed - "jl" and "jg" are for signed numbers, "jb" and "ja" are for unsigned. Since we're doing signed numbers, VAR2 is going to be smallest (since it will be treated as a negative number) and VAR3 will be largest (it is the largest possible signed 16-bit number). If we were doing unsigned, VAR2 would be largest. You may want to explore the difference...

Good point. I tend to ASSume numerical values are signed by default, and unsigned only when explicitly specified. This comes from the fact that I tend to count-down when looping rather than up, so I like to have ((0-1) < 0) rather than ((0-1) > 0). :)

About Bryant Keller
bkeller@about.me

Offline new_geek

  • Jr. Member
  • *
  • Posts: 11
  • Country: 00
hi, thank you for the help, frank and bryant. supposed there is a question, and my feeling is there will be one going to be asked about writing the code to compare them "unsigned"-ly?

Am i just replacing JGs and JLs with JB and JA? Sorry If I'm asking too much :|. The whole assembly language is new to me. But I kinda like it, for me, its like learning how to talk to some one using a whole new language, different set of vocabularies and things  :P ;D

--
best,
geek

edit: I tested the one with unassigned number rule. as the result I got var2 the bigest value and var4 the smallest, is it correct? now I'm tweaking the code right now... Thank you once again for pointing me to the direction :D. I'm becoming more interested in assembly now... :|
« Last Edit: October 29, 2013, 12:15:45 AM by new_geek »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Glad to hear it's going better for you. I'm still having an awful time. I feel like a "clueless newbie" and an "obsolete old man" at the same time. I give myself the same advice I'd give you: "just keep slogging along"...

Your results for the unsigned comparison sound right to me. I attempted, for "extra credit", to print out the results instead of just leaving max and min in ax and dx...

Code: [Select]

; nasm -f elf32 myprog.asm
; ld -o myprog myprog.o -melf_i386

section .data
VAR1:
dw 30000
VAR2:
dw 0ABCDH
VAR3:
dw 7FFFH
VAR4:
dw 100010001000B


; the character '0' will be overwritten with the correct answer as we find it
smax db "VAR0 is signed maximum.", 10
smax_size equ $ - smax

smin db "VAR0 is signed minimum.", 10
smin_size equ $ - smin

umax db "VAR0 is unsigned maximum.", 10
umax_size equ $ - umax

umin db "VAR0 is unsigned minimum.", 10
umin_size equ $ - smin



section .text
global _start

_start:
nop

; find signed maximum, put it in ax
    mov ax, [VAR1]
    mov byte [smax + 3], '1'


    cmp [VAR2], ax
    jle skip1
    mov ax, [VAR2]
    mov byte [smax + 3], '2'
skip1:

    cmp [VAR3], ax
    jle skip2
    mov ax, [VAR3]
    mov byte [smax + 3], '3'
skip2:

    cmp [VAR4], ax
    jle skip3
    mov ax, [VAR4]
    mov byte [smax + 3], '4'
skip3:

; print "result"
    mov edx, smax_size
    mov ecx, smax
    mov ebx, 1
    mov eax, 4
    int 80h


; find signed minimum, put it in dx
    mov dx, [VAR1]
    mov byte [smin + 3], '1'


    cmp [VAR2], dx
    jge skip4
    mov dx, [VAR2]
    mov byte [smin + 3], '2'
skip4:

    cmp [VAR3], dx
    jge skip5
    mov dx, [VAR3]
    mov byte [smin + 3], '3'
skip5:

    cmp [VAR4], dx
    jge skip6
    mov dx, [VAR4]
    mov byte [smin + 3], '4'
skip6:

; print "result"
    mov edx, smin_size
    mov ecx, smin
    mov ebx, 1
    mov eax, 4
    int 80h


; find unsigned maximum, put it in ax
    mov ax, [VAR1]
    mov byte [umax + 3], '1'


    cmp [VAR2], ax
    jbe skip7
    mov ax, [VAR2]
    mov byte [umax + 3], '2'
skip7:

    cmp [VAR3], ax
    jbe skip8
    mov ax, [VAR3]
    mov byte [umax + 3], '3'
skip8:

    cmp [VAR4], ax
    jbe skip9
    mov ax, [VAR4]
    mov byte [umax + 3], '4'
skip9:

; print "result"
    mov edx, umax_size
    mov ecx, umax
    mov ebx, 1
    mov eax, 4
    int 80h


; find unsigned minimum, put it in dx
    mov dx, [VAR1]
    mov byte [umin + 3], '1'


    cmp [VAR2], dx
    jae skip10
    mov dx, [VAR2]
    mov byte [umin + 3], '2'
skip10:

    cmp [VAR3], dx
    jae skip11
    mov dx, [VAR3]
    mov byte [umin + 3], '3'
skip11:

    cmp [VAR4], dx
    jae skip12
    mov dx, [VAR4]
    mov byte [umin + 3], '4'
skip12:

; print "result"
    mov edx, umin_size
    mov ecx, umin
    mov ebx, 1
    mov eax, 4
    int 80h



done:
    mov eax, 1
mov ebx, 0
int 0x80

At the moment, I'm not at all sure it's correct, but it "seems to work". Not necessarily the "best" way to do it.

Although it isn't written as an "array", as long as the variables stay together, it could be treated as an array and the comparisons done in a loop instead of individually. If you had 100 variables instead of just 4, you'd probably want to do that. I may take a crack at that, but... not right now...

Best,
Frank

Edit: Well, already...
Code: [Select]
umin db "VAR0 is unsigned minimum.", 10
umin_size equ $ - smin
should be "$ - umin" of course. I didn't even notice it was printing "too much" at first...

« Last Edit: October 29, 2013, 06:14:23 PM by Frank Kotler »

Offline Bryant Keller

  • Forum Moderator
  • Full Member
  • *****
  • Posts: 360
  • Country: us
    • About Bryant Keller
hi, thank you for the help, frank and bryant. supposed there is a question, and my feeling is there will be one going to be asked about writing the code to compare them "unsigned"-ly?

Am i just replacing JGs and JLs with JB and JA? Sorry If I'm asking too much :|. The whole assembly language is new to me. But I kinda like it, for me, its like learning how to talk to some one using a whole new language, different set of vocabularies and things  :P ;D

As Frank pointed out earlier, JG is signed and JA is unsigned for  "Jump if Greater" and "Jump if Above". Whereas JL is signed and JB is unsigned for "Jump if Lesser" and "Jump if Below". I've adjusted the code to use JA/JB as that's probably what you actually wanted. Also, I think it would be better for you to see what's going on with the registers as the program executes; so I've added a pair of macros (DUMP_INFO and DUMP_VAR) to give you a bit more information. These macros use printf.

Code: [Select]
EXTERN printf

%macro DUMP_VAR 1
%push
%defstr %$var %1
[SECTION .data]
%%varFmt db 9, %$var, " = %u", 10, 0 ;; We are displaying "unsigned" results (%u)
__SECT__
pushad
push %1
push %%varFmt
call printf
add esp, 8
popad
%pop
%endmacro

%macro DUMP_INFO 1
%push
[SECTION .data]
%%infoString db "info: ", %1, 10, 0
__SECT__
pushad
push %%infoString
call printf
add esp, 4
popad
%pop
%endmacro

section .data
VAR1:
dw 30000
VAR2:
dw 0ABCDH
VAR3:
dw 7FFFH
VAR4:
dw 100010001000B

section .bss

section .text
global _start

_start:
nop

; TODO: your code here

;; Clear the registers we will be using.
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0

;; Move our 16-bit data into our registers.
mov ax, [VAR1]
mov bx, [VAR2]

DUMP_INFO "Compare VAR1 [EAX] and VAR2 [EBX]"
DUMP_VAR EAX
DUMP_VAR EBX

cmp ax, bx ; Compare AX and BX
jb axSmaller ; If AX < BX Then Goto axSmaller
ja axBigger ; If AX > BX Then Goto axBigger

;; AX and BX are the same, so we AX to both AX and DX.
mov dx, ax ; If AX = BX Then DX := AX
jmp nextTestVar3

axSmaller:
;; AX is smaller so:
mov dx, ax ; DX := AX
mov ax, bx ; AX := BX
DUMP_INFO "EAX is smaller than EBX"
DUMP_VAR EAX
DUMP_VAR EDX
jmp nextTestVar3

axBigger:
;; AX is bigger so:
; AX := AX (do nothing)
mov dx, bx ; DX := BX
DUMP_INFO "EAX is bigger than EAX"
DUMP_VAR EAX
DUMP_VAR EDX

nextTestVar3:

;; Okay, at this point AX contains the largest of VAR1/VAR2 and DX contains the smallest.
;; We need to test the next variables to see if they will overwrite the current values.

mov cx, [VAR3]

DUMP_INFO "Compare VAR3 [ECX] against MAX [EAX] and MIN [EDX]"
DUMP_VAR ECX
DUMP_VAR EAX
DUMP_VAR EDX

cmp cx, ax ; Compare CX and AX
ja cxBigger ; If CX > AX Then Goto cxBigger

cmp cx, dx ; Compare CX and DX
jb cxSmaller ; If CX < DX Then Goto cxSmaller

;; If we reach this instruction, that means CX was
;; neither greater than AX nor smaller than DX, so we
;; just move on to the next variable.

jmp nextTestVar4

cxSmaller:
;; CX is smaller so:
; AX := AX (do nothing)
mov dx, cx ; DX := CX
DUMP_INFO "ECX is smaller than EDX"
DUMP_VAR EAX
DUMP_VAR EDX
jmp nextTestVar4

cxBigger:
;; CX is bigger so:
mov ax, cx ; AX := CX
; DX := DX (do nothing)
DUMP_INFO "ECX is bigger than EAX"
DUMP_VAR EAX
DUMP_VAR EDX

nextTestVar4:
;; And we now we repeat the processess with VAR4

mov bx, [VAR4]

DUMP_INFO "Compare VAR4 [EBX] against MAX [EAX] and MIN [EDX]"
DUMP_VAR EBX
DUMP_VAR EAX
DUMP_VAR EDX

cmp bx, ax ; Compare BX and AX
ja bxBigger ; If BX > AX Then Goto bxBigger

cmp bx, dx ; Compare BX and DX
jb bxSmaller ; If BX < DX Then Goto bxSmaller

;; If we reach this instruction, that means BX was
;; neither greater than AX nor smaller than DX, so we
;; are done.

jmp done

bxSmaller:
;; BX is smaller so:
; AX := AX (do nothing)
mov dx, bx ; DX := BX
DUMP_INFO "EBX is smaller than EDX"
DUMP_VAR EAX
DUMP_VAR EDX
jmp done

bxBigger:
;; BX is bigger so:
mov ax, bx ; AX := BX
; DX := DX (do nothing)
DUMP_INFO "EBX is bigger than EAX"
DUMP_VAR EAX
DUMP_VAR EDX

done:
;; AX = Largest, DX = Smallest

DUMP_INFO "Final MIN [EAX] and MAX [EDX] States"
DUMP_VAR EAX
DUMP_VAR EDX

;; CHANGED: EAX contains the system call number (SYS_exit = 1) and
;; EBX contains the error code (EXIT_SUCCESS = 0).
mov ebx, 0
mov eax, 1
int 0x80

Expected output would be:
Code: [Select]
bryant@debian:~/Projects/new_geek$ nasm -g -f elf main.asm -o main.o && gcc -nostartfiles -g main.o -o main
bryant@debian:~/Projects/new_geek$ ./main
info: Compare VAR1 [EAX] and VAR2 [EBX]
EAX = 30000
EBX = 43981
info: EAX is smaller than EBX
EAX = 43981
EDX = 30000
info: Compare VAR3 [ECX] against MAX [EAX] and MIN [EDX]
ECX = 32767
EAX = 43981
EDX = 30000
info: Compare VAR4 [EBX] against MAX [EAX] and MIN [EDX]
EBX = 2184
EAX = 43981
EDX = 30000
info: EBX is smaller than EDX
EAX = 43981
EDX = 2184
info: Final MIN [EAX] and MAX [EDX] States
EAX = 43981
EDX = 2184
bryant@debian:~/Projects$
« Last Edit: October 30, 2013, 01:44:11 AM by Bryant Keller »

About Bryant Keller
bkeller@about.me

Offline RaenirS

  • Jr. Member
  • *
  • Posts: 8
I know this is an old topic but I tried to run the code in the latest post in this thread and it gives me errors:

nasm -g -f elf 4TAq1.asm -o 4TAq1.o && gcc -nostartfiles -g 4TAq1.o -o 4TAq1
[myfilename].o: could nott read symbols: File in wrong format
collect2: error: ld returned 1 exit status

« Last Edit: June 17, 2014, 07:31:47 PM by RaenirS »

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Hmmmm... 64-bit system, perhaps? Try adding "-m32" to gcc's command line and see if that helps any.

Best,
Frank