NASM - The Netwide Assembler
NASM Forum => Using NASM => Topic started by: MrCBofBCinTX on July 10, 2010, 08:25:46 PM
-
%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
add esp, byte 3
mov [digit], ax
add ax, [C]
mov [digit], ax
I get:
&8
;
Why is this happening?
-
Impossible to tell without seeing 'system.inc'!
Presumably, it's doing that because that's what you're telling it to do...
%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
-
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:
%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:
%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
-
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...
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'. :)
%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:
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....
%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
-
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! ;)