Author Topic: Problems learning to print and add  (Read 9382 times)

Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Problems learning to print and add
« on: July 10, 2010, 08:25:46 PM »
Code: [Select]
%include    'system.inc'

section .data
digit   db  0, 0, 0Ah
dbytes  equ $-digit
A db '1'
B db 26h
C db 38h

section .text
global  _start
_start:

sub ax, ax
mov ax, [digit]
add ax, [B]
mov [digit], ax

push    dword dbytes
push    dword digit
push    dword stdout
sys.write

;add esp, byte 3
;mov [digit], ax
;add ax, [C]
;mov [digit], ax

push    dword dbytes
push    dword digit
push    dword stdout
sys.write

push    dword 0
sys.exit

As this is, I get an output of:
&8
&8

Question? Why am I not getting:
&
8


Next if I uncomment
Code: [Select]
add esp, byte 3
mov [digit], ax
add ax, [C]
mov [digit], ax

I get:

&8
;

Why is this happening?

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Problems learning to print and add
« Reply #1 on: July 10, 2010, 10:02:13 PM »
Impossible to tell without seeing 'system.inc'!

Presumably, it's doing that because that's what you're telling it to do...

Code: [Select]
%include    'system.inc'  ; ???

section .data
digit   db  0, 0, 0Ah
dbytes  equ $-digit
A db '1'
B db 26h ; or '&'
C db 38h ; or '8'

section .text
global  _start
_start:

sub ax, ax   ; ax = 0
mov ax, [digit]  ; ax = 0
add ax, [B]  ; ax = 3826h
mov [digit], ax ; digit = 26, 38, 0Ah or '&', '8', 0Ah

push    dword dbytes ; length of "digit" = 3
push    dword digit  ; address of "digit"
push    dword stdout ; 1
sys.write ; ??? prints it, evidentally

; depending on what "sys.write" actually does...
; ax = length actually written = 3 ?

; (if uncommented)
;add esp, byte 3 ; stack is badly misaligned
;mov [digit], ax ; digit = 3, 0, 0Ah
;add ax, [C] ; ax = 003Bh
;mov [digit], ax ; digit = 3Bh, 0, 0Ah or ';', 0, 0Ah

push    dword dbytes ; length of "digit" = 3
push    dword digit ; address of "digit"
push    dword stdout ; 1
sys.write ; ??? prints it...

push    dword 0
sys.exit

I'm not sure why you would expect it to do anything different!

Got a link to your 'system.inc'? It does not appear to be the "asmutils" 'system.inc', which is what I'm familiar with.

Why, in the commented code, are you doing "add esp, 3"? Intended to clean up the stack? You've pushed 3 dwords, not 3 bytes! Try "add esp, 3 * 4"... although it won't print anything different. If you did a "ret" anywhere after that, I would expect it to segfault...

Are you forgetting that your variables A, B, and C are one byte, but ax is two bytes?

Best,
Frank


Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: Problems learning to print and add
« Reply #2 on: July 10, 2010, 10:27:03 PM »
I have had a lot of trouble finding any good information that works under OpenBSD.
There is some info for FreeBSD, which works, but not much explanation.
Please point out anything wrong here.
I am getting the output I expected.

Anyway, I have progressed a little:

Code: [Select]
%include    'system.inc'

section .data
digit   dw  0, 0, 'X', 0Ah

dbytes  equ $-digit
A dw 2A00h
B dw 2600h
C dw 3800h

section .text
global  _start
_start:

sub ax, ax
mov ax, [digit]
add ax, [C]
mov [digit], ax

push    dword dbytes
push    dword digit
push    dword stdout
sys.write

mov [digit], ax
add ax, [C]
mov [digit], ax
mov ax, [digit]
add ax, [A]
mov [digit], ax
mov ax, [digit]
add ax, 0100h
mov [digit], ax

push    dword dbytes
push    dword digit
push    dword stdout
sys.write

push    dword 0
sys.exit

system.inc is:

Code: [Select]
%define stdin       0
%define stdout      1
%define stderr      2
%define SYS_nosys   0
%define SYS_exit    1
%define SYS_fork    2
%define SYS_read    3
%define SYS_write   4
%define SYS_open    5
%define SYS_close   6



section    .text
align 4
access.the.bsd.kernel:
    int 80h
    ret

%macro system 1
    mov eax, %1
    call    access.the.bsd.kernel
%endmacro

%macro sys.exit 0
    system  SYS_exit
%endmacro

%macro  sys.fork 0
    system  SYS_fork
%endmacro

%macro  sys.read 0
    system  SYS_read
%endmacro

%macro  sys.write 0
    system  SYS_write
%endmacro

%macro sys.open    0
    system  SYS_open
%endmacro

%macro  sys.close   0
    system  SYS_close
%endmacro

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2667
  • Country: us
Re: Problems learning to print and add
« Reply #3 on: July 11, 2010, 05:17:54 AM »
If you're getting the expected output, that's "good progress", I would say!

I don't know much about the differences between openBSD and freeBSD. I suspect "no difference at all" with the fairly simple code you're doing, but I'm not certain. The freeBSD "handbook" has a really good reputation. I'd go by that, and worry about the differences if and when you encounter any.

I've modified your code slightly so it runs in Linux (difference is small, but important!) I get:

8X
cX

Okay if that's what you want, I guess, but I don't see the "point"... You've enlarged your variables to "dw", so they match ax (two bytes) which is good. I actually meant to suggest that you use al instead of ax - guess I didn't make that very clear.

The "default" register sizes in 32-bit code are 8-bit and 32-bit. To use ax, or any 16-bit register, there needs to be an "operand size override prefix" - the byte 66h. Nasm will provide this, so you don't need to worry about it - don't even need to know it's there. But it is, and adds some "bloat" to your code, for very little advantage. This is because Intel employed a "clever trick" (or a horrid kludge, depending on how you look at it) when they went from 16-bit to 32-bit. The opcodes are exactly the same! If the CPU is in 16-bit mode, it'll use ax, in 32-bit mode (Windows, Linux, or *BSD) it'll use eax - unless that "prefix" is present. (the same prefix will allow you to use eax in 16-bit code, if you care) Sometimes you "need" (or want) to use 16-bit registers in 32-bit code. If you don't, better to stick to al or eax.

You've also expanded your buffer, "digit", to "dw". The size of the buffer, "dbytes" is now 8. You're printing 8 characters, but most of 'em are zeros. Printing a zero - the number 0, not the character '0' - doesn't do anything, so it works "as expected"... but isn't really what you want to do (I don't think).

To start with something much simpler...

Code: [Select]
mov al, 2
add al, 2

Now al = 4, but putting it in a buffer and printing it won't do much. You seem to understand that a "number" and a "character representing that number" aren't the same - or maybe you were just lucky when you used 38h for '8'. :)

Code: [Select]
%include 'system.inc'

section .data
digit db 0, 0Ah
dbytes equ $ - digit

section .text
global _start
_start:

mov al, 2
add al, 2
add al '0' ; or 30h or 48 decimal - all the same
mov [digit], al

push dbytes
push digit
push stdout
sys.write
; add esp, 12

push 0
sys.exit

That's untested, but if I haven't screwed it up, it should work. Now, step it up a notch:

Code: [Select]
mov al, 21
add al, 21

Now al = 42 ("the answer"), but adding '0' to it isn't going to help! We need to print the character '4', and then the character '2'. Dividing by ten would give a quotient of 4 and a remainder of 2. We could use that - both would need to have '0' added to "convert" them to charcters. Ummm....

Code: [Select]
%include 'system.inc'

section .data
digit db 0, 0, 0Ah ; note increased size!
dbytes equ $ - digit

section .text
global _start
_start:

mov al, 21
add al, 21

mov bl, 10
mov ah, 0 ; make sure it's zero! "div" uses it!
div bl  ; quotient in al = 4, remainder in ah = 2

add al '0'
mov [digit], al
add ah, '0'
mov [digit + 1], ah

push dbytes
push digit
push stdout
sys.write
; add esp, 12

push 0
sys.exit

More likely that I've screwed that one up, but it might still work. :)

Still not very useful - it'll only do two digits. For more "general" use, you probably want to use 32-bit registers, and extract the digits in a loop. I have an "example" I use, but it is rather specific to Linux - "expects" the length in edx and the buffer address in ecx, so it isn't too easily adapted to BSD. I'll see if I can come up with something, but not right now.

Fortunately, the "add" instruction is pretty easy, the "print" part is the hard part.

Best,
Frank


Offline MrCBofBCinTX

  • Jr. Member
  • *
  • Posts: 18
    • Capuchado!
Re: Problems learning to print and add
« Reply #4 on: July 11, 2010, 10:27:34 AM »
yes, after that I made it work with al and then ah only.
Your example worked fine, except for missing comma.

Using al or eax is a good tip, thanks

Info for BSD's is harder to find. OpenBSD does have close to perfect man pages, which I now see is very useful, as I figured out some examples from FreeBSD handbook.
I am guessing that if I can just get to a certain point, I will be able to figure things out on my own.

As I am also working on getting proficient at using C, I also want to learn how all of it works in assembly.
What I have noticed is that most people seem to be learning assembly as part of some class, not me.
I first learned a little assembly with my Timex Sinclair when I was a kid. Couldn't quite get my head around some of it back then though!  ;)