flat assembler
Message board for the users of flat assembler.
Index
> Windows > Learning Assembly Goto page 1, 2 Next |
Author |
|
revolution 30 Mar 2017, 02:41
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. |
|||
30 Mar 2017, 02:41 |
|
revolution 30 Mar 2017, 02:46
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 |
|||
30 Mar 2017, 02:46 |
|
C0deHer3tic 30 Mar 2017, 03:52
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: 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. - |
|||
30 Mar 2017, 03:52 |
|
C0deHer3tic 30 Mar 2017, 04:00
revolution wrote: It is complicated. Especially the floating point conversions. 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. - |
|||
30 Mar 2017, 04:00 |
|
revolution 30 Mar 2017, 04:50
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. |
|||
30 Mar 2017, 04:50 |
|
C0deHer3tic 30 Mar 2017, 05:48
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 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 Code: push edx Code: cmp ecx, 1 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 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:
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. - |
|||
30 Mar 2017, 05:48 |
|
revolution 30 Mar 2017, 05:55
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. |
|||
30 Mar 2017, 05:55 |
|
Furs 30 Mar 2017, 10:43
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 reg, reg Code: test reg, reg And xor is not or. You know the XOR operation in C? The ^ operator? XOR = ^ OR = | AND (or TEST) = & That's their C equivalence. |
|||
30 Mar 2017, 10:43 |
|
C0deHer3tic 30 Mar 2017, 20:59
@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. - |
|||
30 Mar 2017, 20:59 |
|
C0deHer3tic 30 Mar 2017, 21:09
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. |
|||
30 Mar 2017, 21:09 |
|
revolution 30 Mar 2017, 23:55
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. |
|||
30 Mar 2017, 23:55 |
|
C0deHer3tic 31 Mar 2017, 02:01
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. - |
|||
31 Mar 2017, 02:01 |
|
revolution 31 Mar 2017, 08:14
Step 5 should be:
5. Copy EAX into ECX |
|||
31 Mar 2017, 08:14 |
|
C0deHer3tic 31 Mar 2017, 08:51
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 eax, al ; fails mov al, ah ; both are 8 bit mov ax,ah ; fails mov ecx, ebx both are 32 bit mov ax, bx ; both 16 bit etc.... I also am learning the looping uses flags, or comparing registers. Code: mov ebx, 8 loop_1: dec ebx push ebx cmp ebx, 0 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 |
|||
31 Mar 2017, 08:51 |
|
C0deHer3tic 31 Mar 2017, 08:52
revolution wrote: Step 5 should be: Yes, I made a typo. _________________ - Just because something is taught one way, does not mean there is not a different way, possibly more efficient. - |
|||
31 Mar 2017, 08:52 |
|
revolution 31 Mar 2017, 09:55
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. |
|||
31 Mar 2017, 09:55 |
|
Furs 31 Mar 2017, 12:11
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. 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... |
|||
31 Mar 2017, 12:11 |
|
C0deHer3tic 01 Apr 2017, 00:20
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. - |
|||
01 Apr 2017, 00:20 |
|
revolution 01 Apr 2017, 00:32
Look for the Intel and AMD manuals.
|
|||
01 Apr 2017, 00:32 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.