flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Windows > Learning Assembly

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
Learning Assembly
What is the assembly equivalent of printf?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 30 Mar 2017, 02:39
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
It is complicated. Especially the floating point conversions.

Would you be interested in just a subset of what printf can do as a start?

A simple conversion to decimal might be a good place to start.
Post 30 Mar 2017, 02:41
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
From the fasm sources we can find this code to print a decimal number to the console:

Code:
display_number:
        push    ebx
        mov     ecx,1000000000
        xor     edx,edx
        xor     bl,bl
      display_loop:
        div     ecx
        push    edx
        cmp     ecx,1
        je      display_digit
        or      bl,bl
        jnz     display_digit
        or      al,al
        jz      digit_ok
        not     bl
      display_digit:
        mov     dl,al
        add     dl,30h
        push    ecx
        call    display_character
        pop     ecx
      digit_ok:
        mov     eax,ecx
        xor     edx,edx
        mov     ecx,10
        div     ecx
        mov     ecx,eax
        pop     eax
        or      ecx,ecx
        jnz     display_loop
        pop     ebx
        ret

display_character:
        push    ebx
        mov     [character],dl
        push    [con_handle]
        call    [GetStdHandle]
        mov     ebx,eax
        push    0
        push    bytes_count
        push    1
        push    character
        push    ebx
        call    [WriteFile]
        pop     ebx
        ret

Post 30 Mar 2017, 02:46
View user's profile Send private message Visit poster's website Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49

Code:

display_number
        push    ebx     
        mov     ecx,1000000000
        xor     edx,edx 
        xor     bl,bl 




Just looking at this here, I see that I have a lot to learn.

We push ebx to the stack. Why?
EBX is the base point for the data section. Correct?

Then we mov 1 billion to ecx. Why?
ECX - Counter for string and loop operations

So the loop counter is equal to 1 billion?

"PC Assembly Language Paul A. Carter March 20, 2005"(page 61)-http://www.scs.stanford.edu/05au-cs240c/lab/pcasm-book.pdf

Quote:
3.2.3 The XOR operation The exclusive OR of 2 bits is 0 if and only if both bits are equal, else the result is 1 as the truth table in Table 3.3 shows. Below is a code example:

Code:

mov ax0C123H
xor ax0E831H ; ax = 2912H




So therefore the edx or bl either becomes 0 or 1?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 30 Mar 2017, 03:52
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49

revolution wrote:
It is complicated. Especially the floating point conversions.

Would you be interested in just a subset of what printf can do as a start?

A simple conversion to decimal might be a good place to start.



I am interested in learning what is to be learned. However I would prefer if we pretend assembly is the only language that exists, and start like that.

I just need to know the right direction to head, and I tried to say that in my other thread. Where would you point me?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 30 Mar 2017, 04:00
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
Don't try to interpret the register names as anything special. We can use eax or ecx or edi etc. for any purpose we wish to. In the case above ecx is not a loop counter, it is a divisor to extract the digits. It starts at 1e9 because the most significant digit of a 32-bit number can be no more than 4e9. So it extracts the first digit. Then divides the divisor by 10 (now 1e8) and extracts the next digit. And so on until the very last digit with a divisor of 1. Plus there is a bit of code to suppress leading zeros.

As for the xor: It is a shortcut used to make a register value zero. xor reg,same_reg will always leave the register as zero. You could also write mov reg,0.

And the push ebx is merely to make sure the value is not altered when returning to the caller. You can see the pop ebx just before the ret.
Post 30 Mar 2017, 04:50
View user's profile Send private message Visit poster's website Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49

Code:

display_number:
        push    ebx
        mov     ecx,1000000000
        xor     edx,edx
        xor     bl,bl
;-----^Explained------------
      display_loop:
        div     ecx
        push    edx
        cmp     ecx,1
        je      display_digit
        or      bl,bl
        jnz     display_digit
        or      al,al
        jz      digit_ok
        not     bl



Okay so

Code:
div ecx

does what?
You said, "Then divides the divisor by 10 (now 1e8) and extracts the next digit." Why 10?

"PC Assembly Language Paul A. Carter March 20, 2005"(page 44)-http://www.scs.stanford.edu/05au-cs240c/lab/pcasm-book.pdf

Quote:
The two division operators are DIV and IDIV. They perform unsigned
and signed integer division respectively. The general format is:

Code:
div source


If the source is 8-bit, then AX is divided by the operand. The quotient is
stored in AL and the remainder in AH. If the source is 16-bit, then DX:AX
is divided by the operand. The quotient is stored into AX and remainder
into DX. If the source is 32-bit, then EDX:EAX is divided by the operand
and the quotient is stored into EAX and the remainder into EDX. The IDIV
instruction works the same way. There are no special IDIV instructions like
the special IMUL ones. If the quotient is too big to fit into its register or the
divisor is zero, the program is interrupted and terminates. A very common
error is to forget to initialize DX or EDX before division.



Code:
push edx

This is 0, right?

Code:

cmp ecx1
jnz display_digit



If ecx = 1 goto label display_digit.
je (jump equal = jump if ecx is 1) if I am understanding right.

Code:

or      bl,bl 
jnz     display_digit 




Now here is where it gets confusing....

Code:
or bl,bl

could be this?

Code:
mov bl,0


If bl is 0, then why say if not zero go to display_digit? What is happening here?
Then this:

Code:

or      al,al 
jz      digit_ok 
not     bl



0 out al
jump if zero to digit_ok?

Ah and then this (not) operation....
"PC Assembly Language Paul A. Carter March 20, 2005"(page 61)-http://www.scs.stanford.edu/05au-cs240c/lab/pcasm-book.pdf

Quote:

3.2.4 The NOT operation
The NOT operation is a unary operation (i.e. it acts on one operand,
not two like binary operations such as AND). The NOT of a bit is the
opposite value of the bit as the truth table in Table 3.4 shows. Below is a
code example:

Code:

mov ax0C123H
not ax ; ax = 3EDCH



Note that the NOT finds the one’s complement. Unlike the other bitwise
operations, the NOT instruction does not change any of the bits in the FLAGS
register.



I hope my questions are not too bothersome, and I appreciate your time and effort to explain to me.

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 30 Mar 2017, 05:48
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
There are two div instructions in the source. The first is to extract the next digit, the second is to adjust ecx for the next divisor.

or bl,bl is used to set the flags. bl is not altered. So we can test if bl is zero by using or bl,bl. We can also write cmp bl,0. Note this is not the same as xor bl,bl.

jnz means jump if not zero. jz means jump if zero.
Post 30 Mar 2017, 05:55
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 821
x86 keeps track of an extra register called the FLAGS register (or EFLAGS/RFLAGS, whatever). This gets updated on specific instructions to reflect usually the output of those instructions.

For example, the zero flag is usually set if the destination (first operand) is zero, in instructions that use it.

But to really understand how it works, you need to look up the specifics of an instruction you don't know. Otherwise there's no point.

Check this site and bookmark it, it has easy to browse instructions: http://www.felixcloutier.com/x86/ (you don't have to memorize all instructions there, don't treat it as that way, just as a reference/bookmark... in time you will learn to memorize the most commonly used instructions, don't worry about it)

You can of course also download official Intel Manual but that's .pdf and harder to search...

Each instruction should say what flags it affects at the end of the description. ZF = zero flag, CF = carry flag, SF = sign flag, OF = overflow flag.

So then a jump like jz (or je which is the same instruction!) will simply jump if and only if ZF is set. ZF can be set based on previous instructions.


Code:
or regreg

Doesn't change the contents of 'reg' (logical OR with itself always gives the same value), but it does update the flags based on reg. A better way is to use

Code:
test regreg

which is the same thing.

And xor is not or.

You know the XOR operation in C? The ^ operator?

XOR = ^
OR = |
AND (or TEST) = &

That's their C equivalence.
Post 30 Mar 2017, 10:43
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
@revolution
I see my mistake of not noticing the difference between XOR and OR. Thank you for pointing that out, as well as explaining the other operations.

@Furs
I bookmarked and download the pdf. Thank you for showing me that, this is a lot to digest, and very different from learning HLLs.

Code:

display_digit
        mov     dl,al 
        add     dl,30h 
        push    ecx 
        call    display_character 
        pop     ecx 
      digit_ok
        mov     eax,ecx 
        xor     edx,edx 
        mov     ecx,10 
        div     ecx 
        mov     ecx,eax 
        pop     eax 
        or      ecx,ecx 
        jnz     display_loop 
        pop     ebx 
        ret



So from what I understand, display digit does the following:
======================================
1. Copies AL (8 bit register) into DL (8 bit register)
2. Add the hex value 30 to DL
3. Push ECX to the stack
4. Call display_character
4. Pop the stored ECX
======================================
And digit_ok does:
======================================
1. Copies ECX into EAX
2. EDX is made 0
3. Store the decimal value of 10 inside ECX
4. Divide ECX*
5. Copy ECX into EAX
6. Pop EAX out of the stack (restore)
7. Compare if ECX is 0
8. If not 0, jump to display_loop
9. Pop EBX (restore)
10. End function
======================================


*(I must say I am not understanding the DIV Operation. What is it dividing by? Is this hard coded or can you specify?)

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 30 Mar 2017, 20:59
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
Like for example, what if I wanted to do 3 divided by 6, or 123 divided by 17?

Oh and I have no idea how to run that code, but learning the program flow is good. Razz
Post 30 Mar 2017, 21:09
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
C0deHer3tic: DIV is a machine instruction. Divide. You already posted the description previosuly. "If the source is 32-bit, then EDX:EAX is divided by the operand and the quotient is stored into EAX and the remainder into EDX."

When you don't understand an instruction like DIV you can always read the canonical sources from AMD / Intel. Or even a simple web search will tell you detailed answers. There is no need to wait for hours for people here to respond. You can know immediately.
Post 30 Mar 2017, 23:55
View user's profile Send private message Visit poster's website Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
My bad, I had found the answer. Should have said something. Thank you, revolution.

Was I right about the code though?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 31 Mar 2017, 02:01
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
Step 5 should be:

5. Copy EAX into ECX
Post 31 Mar 2017, 08:14
View user's profile Send private message Visit poster's website Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
Alright, so I have been studying the registers, and the operations that can be done with them. The code you posted on how to print a decimal number to the console is now understood. However I would not know where to go from there.

What would you recommend?

I can do basic math with FASM, but cannot output anything to the console, unless of course using printf (which I learned before). I now know how to store values in the registers, being either 8 bit, 16 bit, or 32 bit. I have also learned you cannot copy registers that are different sizes.


Code:

mov eaxal ; fails
mov alah ; both are 8 bit
mov ax,ah ; fails
mov ecxebx both are 32 bit
mov axbx ; both 16 bit
etc....




I also am learning the looping uses flags, or comparing registers.

Code:

mov ebx8
loop_1:
                dec ebx
                push ebx
                cmp ebx0
                jnz loop_1



This will loop until Zero Flag is set.

What should I learn now?

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -


Last edited by C0deHer3tic on 31 Mar 2017, 08:53; edited 1 time in total
Post 31 Mar 2017, 08:51
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49

revolution wrote:
Step 5 should be:

5. Copy EAX into ECX



Yes, I made a typo. Razz

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 31 Mar 2017, 08:52
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
The code I posted above from the fasm sources will print to the console without printf. It uses GetStdHandle and WriteFile. So you can too.

And your code for the looping example pushes ebx each time around the loop. But no associated pops are present. You will overflow the stack if you do that too many times. And note that the dec instruction also sets the Z flag so you don't need the following cmp.

C0deHer3tic wrote:
I have also learned you cannot copy registers that are different sizes.

Have a look at the movzx and movsx instructions.
Post 31 Mar 2017, 09:55
View user's profile Send private message Visit poster's website Reply with quote
Furs



Joined: 04 Mar 2016
Posts: 821

C0deHer3tic wrote:
I bookmarked and download the pdf. Thank you for showing me that, this is a lot to digest, and very different from learning HLLs.

Just treat it as a reference. You don't memorize all APIs in C either do you? When you have doubts of an instruction use, look it up in the reference. (CTRL+F in that page)

In time, you will memorize the most commonly used instructions and "tricks", just like you memorize the most commonly used APIs.

There's no shame in having a reference at hand, I look at it all the time personally for more obscure instructions...
Post 31 Mar 2017, 12:11
View user's profile Send private message Reply with quote
C0deHer3tic



Joined: 25 Mar 2017
Posts: 49
I looked in the Pcasm book and could not find the movsx or movzx command. However I found this, http://www.c-jump.com/CIS77/ASM/DataTypes/T77_0270_sext_example_movsx.htm

I thank you both for the responses. You guys/gals are helping me.

_________________
- Just because something is taught one way, does not mean there is not a different way, possibly more efficient. -
Post 01 Apr 2017, 00:20
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 15162
Location: GW170817
Look for the Intel and AMD manuals.
Post 01 Apr 2017, 00:32
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.