flat assembler
Message board for the users of flat assembler.
![]() Goto page Previous 1, 2, 3, 4, 5, 6, 7 Next |
Author |
|
dancho 30 Mar 2012, 18:01
getchar reads one ( 1 ) character from stdin,
use gets or gets_s or fgets for reading a string, then something from ato* family to convert string to number... something like this: Code: format PE console 5.0 entry cmain include 'win32axp.inc' section '.text' code readable executable cmain: cinvoke printf,<'Enter a number :',0> cinvoke gets,buffer cinvoke atoi,buffer mov [num],eax cinvoke printf,<'Number is %u',0>,[num] invoke ExitProcess,0 section '.data' data readable writeable num rd 1 buffer rb 32 section '.idata' import data readable library kernel32,'kernel32.dll',\ msvcrt,'msvcrt.dll' include 'api\kernel32.inc' include 'api\msvcrt.inc' and you will have to use some debugger ( ollydbg is popular ) to see how exactly fasm do his magic and compile this code into exe file... |
|||
![]() |
|
AsmGuru62 30 Mar 2012, 19:07
I think if you want multiply EAX by itself it would be: "IMUL EAX,EAX".
|
|||
![]() |
|
bzdashek 30 Mar 2012, 20:36
dancho wrote: getchar reads one ( 1 ) character from stdin, Unable to compile for some reason, tried different variants, but th error persists. So sad. Code: C:\Users\gilyazov\Documents\Programs\fasm\INCLUDE/api_ext\msvcrt.inc [1]: import msvcrt,\ C:\Users\gilyazov\Documents\Programs\fasm\INCLUDE/macro/import32.inc [31] import [5]: if used label error: reserved word used as symbol. |
|||
![]() |
|
bzdashek 30 Mar 2012, 21:04
This one works:
Code: format PE console entry cmain include 'win32axp.inc' cmain: cinvoke printf,<'Enter a number :',0> cinvoke gets,buffer cinvoke atoi,buffer mov [num],eax cinvoke printf,<'Number is %u',0>,[num] ;cinvoke exit,0 invoke ExitProcess,0 section '.data' data readable writeable buffer rb 32 num rd 1 section '.idata' data import readable library msvcrt,'MSVCRT.DLL',\ kernel32,'KERNEL32.DLL' import msvcrt,\ printf,'printf',\ exit,'_exit',\ gets,'gets',\ atoi,'atoi' import kernel32,\ ExitProcess,'ExitProcess' |
|||
![]() |
|
Inagawa 31 Mar 2012, 07:13
Okay, I will play with this for a long time, just tell me one thing, bzdashek. Why did you put buffer and num into .data and not .bss? Shouldn't uninitialized variables go into .bss? Thanks a lot
Last edited by Inagawa on 31 Mar 2012, 13:26; edited 2 times in total |
|||
![]() |
|
bzdashek 31 Mar 2012, 11:35
Inagawa wrote: Okay, I will play with this for a long time, just tell me one thing, bzdashek. Why did you put buffer and num into .data and not .bss? Shouldn't unitialized values go into .bss? Thanks a lot Inagawa, douzo yoroshiku onegaishimasu. I put it there for no reason, since I was unaware about this convention - placing uninit data in .bss. For operating system it's no difference. You can name your segments whatever you like, since name doesn't matter. I believe it's just a good style of programming to name them '.code', '.data', '.bss' etc. Someone correct me if I'm mistaken. |
|||
![]() |
|
dancho 31 Mar 2012, 17:29
hmm opera cache is playing games with me,
sry mods plz delete... |
|||
![]() |
|
Inagawa 01 Apr 2012, 06:42
Haha I posted a program, but I decided to expand it and learn more before writing and asking stuff here again. So maybe you caught a glimpse before I deleted it.
|
|||
![]() |
|
Inagawa 01 Apr 2012, 16:08
Code: format PE console entry cmain include 'win32axp.inc' ;============================================================================= section '.data' data readable writeable __separatorMsg db '=========================================', 10, 0 __promptMsg db '> Enter a number: ', 0 __resultMsg db '=> Result is %i', 10, 0 __addMsg db '> Addition: (0 + Input)', 10, 0 __subMsg db '> Subtraction: (100 - Input)', 10, 0 __mulMsg db '> Multiplication: (Input * Input)', 10, 0 __divMsg db '> Division: (100 / Input)', 10, 0 __negMsg db '> Negation: (Input * (-1))', 10, 0 __64addMsg db '> 64bit Addition (Input + 2147483647)', 10, 0 __64subMsg db '> 64bit Subtraction (2147483647 - Input)', 10, 0 __jumpMsg db '> Jumping (Input >= 50 =< Input)', 10, 0 __jumpGMsg db '=> More than 50.', 10, 0 __jumpLMsg db '=> Less than 50.', 10, 0 __jumpEMsg db '=> Equal to 50.', 10, 0 __loopMsg db '> Looping (Msg * Input)', 10, 0 __primeMsg db '> Finding prime numbers', 10, 0 __shiftMsg db '> Shifting (Input * 4, Input / 4)', 10, 0 __shiftLMsg db '=> Shifted Left by 2: %i', 10, 0 __shiftRMsg db '=> Shifted Right by 2: %i', 10, 0 __rotationMsg db '> Rotations (Input * 4, Input / 4)', 10, 0 __subprogMsg db '> Subprogram', 10, 0 __subprogResMsg db '=> Subprogram returned.', 10, 0 ;============================================================================= section '.bss' data readable writeable __buffer rb 32 __input rd 1 ;============================================================================= section '.text' code readable executable cmain: ;=== GET INPUT ================================= cinvoke printf, __promptMsg ; Print out prompt cinvoke gets, __buffer ; Read string into buffer cinvoke atoi, __buffer ; Store converted into EAX mov [__input], eax ; Move EAX to input cinvoke printf, __separatorMsg ; Print out the separator ;=== ADDITION ================================== cinvoke printf, __addMsg ; Print out the message xor eax, eax ; Zero out EAX add eax, [__input] ; Add input to EAX cinvoke printf, __resultMsg, eax ; Print out the result cinvoke printf, __separatorMsg ; Print out the separator ;=== SUBTRACTION =============================== cinvoke printf, __subMsg ; Print out the message mov eax, 100 ; Init EAX with 100 sub eax, [__input] ; Add input to EAX cinvoke printf, __resultMsg, eax ; Print out the result cinvoke printf, __separatorMsg ; Print out the separator ;=== MULTIPLICATION ============================ cinvoke printf, __mulMsg ; Print out the message mov eax, [__input] ; Load the input into EAX imul eax ; Multiply EAX by itself cinvoke printf, __resultMsg, eax ; Print out the result cinvoke printf, __separatorMsg ; Print out the separator ;=== DIVISION ================================== cinvoke printf, __divMsg ; Print out the message mov ecx, [__input] ; Load the input into EAX cdq ; Extend EAX into EDX:EAX mov eax, 100 ; Init EAX with 100 idiv ecx ; Divide EAX by ECX cinvoke printf, __resultMsg, eax ; Print out the result cinvoke printf, __separatorMsg ; Print out the separator ;=== NEGATION ================================== cinvoke printf, __negMsg ; Print out the message mov eax, [__input] ; Load the input into EAX neg eax ; Negate EAX cinvoke printf, __resultMsg, eax ; Print out the result cinvoke printf, __separatorMsg ; Print out the separator ;=== 64bit ADDITION ============================ ;cinvoke printf, __64addMsg ; Print out the message ;mov eax, 2147483647 ; Init EAX with 2147483647 ;mov ecx, [__input] ; Init ECX with input ;add eax, ecx ; Add the lower half ;xor edx, edx ; Zero out EDX ;xor ebx, ebx ; Zero out EBX ;adc edx, ebx ; Add the upper half ;cinvoke printf, __resultMsg, edx:eax ; Print out the result ;cinvoke printf, __separatorMsg ; Print out the separator ;=== JUMPS ===================================== cinvoke printf, __jumpMsg ; Print out the message mov eax, [__input] ; Move input to EAX cmp eax, 50 ; Compare EAX to 50 jg more50 ; Jump if EAX > 50 jl less50 ; Jump if EAX < 50 je equal50 ; Jump if EAX == 50 more50: cinvoke printf, __jumpGMsg ; Print out result jmp jumpEnd ; Skip the rest less50: cinvoke printf, __jumpLMsg ; Print out result jmp jumpEnd ; Skip the rest equal50: cinvoke printf, __jumpEMsg ; Print out result jumpEnd: cinvoke printf, __separatorMsg ; Print out the separator ;=== LOOPING =================================== ;cinvoke printf, __loopMsg ; Print out the message ;mov ecx, [__input] ; Init ECX with input ;loopStart: ;cinvoke printf, <'Hello', 10, 0> ; DOES NOT WORK, BUT WHY? ;loop loopStart ; Loopback until ECX == 0 ;cinvoke printf, __separatorMsg ; Print out the separator ;=== FIND PRIME NUMBERS ======================== ;cinvoke printf, __primeMsg ; Print out the message ;mov eax, 2 ; Init EAX with 2 ;cinvoke printf, __resultMsg, eax ; Special case ;mov eax, 3 ; Init EAX with 3 ;cinvoke printf, __resultMsg, eax ; Special case ;mov edx, 5 ; First guess at a prime ;while_limit: ;mov eax, edx ; Move the guess to EAX ;cmp eax, [__input] ; Compare guess to limit ;jnbe end_while_limit ; If out-of-bounds, jump ;mov ebx, 3 ; Move factor into EBX ;while_factor: ;mov eax, ebx ; Move the factor to EAX ;mul eax ; Multiply EAX by itself ;jo end_while_limit ; Result > 32bit ;cmp eax, edx ; Compare factor to guess ;jnb end_while_factor ; Jump if factor^2 > guess ;mov eax, edx ; Move guess into EAX ;push edx ; Push EDX no stack ;xor edx, edx ; Zero out EDX ;div ebx ; Divide EDX:EAX by EBX ;cmp edx, 0 ; Compare EDX to zero ;je end_while_factor ; Jump if EDX == 0 ;add ebx, 2 ; Add 2 to factor ;jmp while_factor ; Repeat the loop ;end_while_factor: ;je end_if ; Jump if guess/factor == 0 ;pop edx ; Take back guess from stack ;mov eax, edx ; Move guess into EAX ;end_if: ;add edx, 2 ; Add 2 to EDX ;jmp while_limit ; Jump back ;end_while_limit: ;cinvoke printf, __separatorMsg ; Print out the separator ;=== SHIFTS ==================================== cinvoke printf, __shiftMsg ; Print out the message mov eax, [__input] ; Load the input into EAX push eax ; Push EAX into stack sal eax, 2 ; Shift EAX 2 bits left cinvoke printf, __shiftLMsg, eax ; Print out result of SAL pop eax ; Pop EAX from stack sar eax, 2 ; Shift EAX 2 bits right cinvoke printf, __shiftRMsg, eax ; Print out result of SAR cinvoke printf, __separatorMsg ; Print out the separator ;=== ROTATIONS ================================= cinvoke printf, __rotationMsg ; Print out the message mov eax, [__input] ; Load the input into EAX push eax ; Push EAX into stack rol eax, 2 ; Rotate EAX 2 bits left cinvoke printf, __shiftLMsg, eax ; Print out result of SAL pop eax ; Pop EAX from stack ror eax, 2 ; Rotate EAX 2 bits right cinvoke printf, __shiftRMsg, eax ; Print out result of SAR cinvoke printf, __separatorMsg ; Print out the separator ;=== SUBPROGRAMS =============================== cinvoke printf, __subprogMsg ; Print out the message mov eax, [__input] ; Load the input into EAX call printResult ; Call printResult ;=== LEAVE CONSOLE OPEN ======================== cinvoke getchar ; Leave console open cinvoke exit, 0 ; C-Style exit ?? ;============================================================================ section '.text' code executable readable ;=== PRINT RESULT SUBPROGRAM ===================== printResult: push ebp ; Store EBP mov ebp, esp ; Init EBP with ESP cinvoke printf, __subprogResMsg ; Print out the result mov esp, ebp ; Restore ESP pop ebp ; Restore EBP ret ; Return ;============================================================================= section '.idata' data import readable library msvcrt,'MSVCRT.DLL',\ kernel32,'KERNEL32.DLL' import msvcrt,\ printf,'printf',\ getchar,'_fgetchar',\ exit,'_exit',\ gets,'gets',\ atoi,'atoi',\ atof,'atof' import kernel32,\ ExitProcess,'ExitProcess' Okay, this is the finished version of my 'programming journey' (so far, ofc). I am on the page 87, about to tackle multi-module programs and the code so far is so long that it would hinder me, so I'll start fresh. I've learned a few things, but there is much that confuses me (the commented-out code). I know the 64bit addition is completely wrong, so that aside, what about the looping? I know that printf actually pushes the address of the message and then calls something to print it out, but that should only modify EAX, no? (My god how long it took me to find why my EAX register had weird values after printing out something ![]() About subprograms. I had to move my function body into a segment of its own to avoid having it 'automatically' called without invocation - is this a normal practice? (Maybe it is a premature question, as I'll probably get an answer in the multi-module part of the book.) Anyway, thanks for any advice I might get and sorry for the long post/code ![]() |
|||
![]() |
|
ProphetOfDoom 02 Apr 2012, 00:37
I can't run your code as I'm not using Windows but I glanced over it quickly. The looping problem is probably due to the printf function overwriting the ecx register. There are IIRC three registers on x86 known as "scratch" registers - they are not guaranteed to remain the same across function calls. They are eax, ecx, and edx. So you could fix the problem by using another register as your loop counter such as ebx, combined with a "jnz" instruction. Alternatively you could "push ecx" before your function call and "pop ecx" afterwards to restore its value.
About the putting functions in sections thing... no, you wouldn't normally put each function in its own section. Just be aware that execution will always "fall through" to the next instruction. If you have a call to "exit" followed by your own function, the function won't be executed. I don't know if fasm merges sections with the same name, it may do (I think most linkers do), but the result you got from having the function in its own section is probably accidental and not the way to do it. |
|||
![]() |
|
Inagawa 02 Apr 2012, 08:43
I see. I was stupid to think that printf does not modify ECX. After all, it has to count a loop to print out the individual characters.
I know that execution falls through, but I have to separate functions into their segments, or I would have to use a redundant jump over the function body. If I call FUNC from CODE, once the FUNC returns, it will continue it's execution over FUNC without actually being invoked, trampling over data and then the RET instruction will actually end the program itself, closing the console. This is precisely what happened to me. What is the solution, then? ;==CODE== ;==FUNC== |
|||
![]() |
|
bzdashek 02 Apr 2012, 09:59
On my machine runs OK. But what do you mean by 'automatically called'? Since procedure is located after exit() call, it won't run unless it's called manually
|
|||
![]() |
|
Inagawa 02 Apr 2012, 12:58
It is now. But before that the code looked like this.
Code: ;=== SUBPROGRAMS =============================== cinvoke printf, __subprogMsg ; Print out the message mov eax, [__input] ; Load the input into EAX call printResult ; Call printResult printResult: push ebp ; Store EBP mov ebp, esp ; Init EBP with ESP cinvoke printf, __subprogResMsg ; Print out the result mov esp, ebp ; Restore ESP pop ebp ; Restore EBP ret ; Return ;=== LEAVE CONSOLE OPEN ======================== cinvoke getchar ; Leave console open cinvoke exit, 0 ; C-Style exit ?? And once the printResult returned, the execution fell into the printResult again, since it was placed below it. And since Prophet tells me "placing every function into its own segment is wrong", I have no idea what to actually do other than place a jmp after the call to printResult, but that would be unsightly.. ![]() |
|||
![]() |
|
Inagawa 02 Apr 2012, 15:18
Haha anyway, forget the previous problems, look at what I programmed. I am proud of myself, since I didn't use any tutorials, only my knowledge so far. I will expand on this (sort numbers from highest to lowest, compute median, etc.) later.
![]() Code: format PE console entry cmain include 'win32axp.inc' ;============================================================================= section '.data' data readable writeable __separatorMsg db '==========================================================', 10, 0 __promptMsg db '> Enter a number (negative ends input): ', 0 __resultMsg db '=> %i', 10, 0 __arrayMsg db '> Here is the content of the Array: ',10, 0 ;============================================================================= section '.bss' data readable writeable __buffer rb 32 __array rd 64 ;============================================================================= section '.text' code readable executable cmain: ;=== GET INPUT ================================= xor ebx, ebx ; Zero out EBX inputLoop: cinvoke printf, __promptMsg ; Print out prompt cinvoke gets, __buffer ; Get string into buffer cinvoke atoi, __buffer ; Convert string to number cmp eax, 0 ; Compare EAX(input) with 0 jl endInputLoop ; Terminate if EAX(input) < 0 mov [__array+ebx], eax ; Store the input in array add ebx, 4 ; Increase the pointer by 4 cmp eax, 0 ; Compare EAX(input) to 0 jge inputLoop ; Repeat if EAX(input) >= 0 endInputLoop: cinvoke printf, __separatorMsg ; Print out the separator cinvoke printf, __arrayMsg ; Print out the message mov ecx, 4 ; Init divisor(ECX) with 4 mov eax, ebx ; Init EAX(dividend) with EBX cdq ; Extend EAX into EDX:EAX idiv ecx ; EAX / 4 = number of arguments mov ecx, eax ; Move the number into ECX mov ebx, __array ; Init EBX with the adress of array loopArr: push ecx ; Store ECX cinvoke printf, __resultMsg, DWORD [ebx] ; Print out the array at EBX add ebx, 4 ; Increase EBX by 4 bytes pop ecx ; Restore ECX loop loopArr ; Repeat cinvoke printf, __separatorMsg ; Print out the separator ;=== LEAVE CONSOLE OPEN ======================== cinvoke getchar ; Leave console open cinvoke exit, 0 ; C-Style exit ?? ;============================================================================= section '.idata' data import readable library msvcrt,'MSVCRT.DLL',\ kernel32,'KERNEL32.DLL' import msvcrt,\ printf,'printf',\ getchar,'_fgetchar',\ exit,'_exit',\ gets,'gets',\ atoi,'atoi',\ atof,'atof' import kernel32,\ ExitProcess,'ExitProcess' |
|||
![]() |
|
Inagawa 05 Apr 2012, 15:40
Okay, so here am I again. This time about floating point multiplication.
Code: ;=== FLOAT MULTIPLICATION SUBROUTINE =========== %FMul%: push ebp lea ebp, [esp+4] sub esp, 0 cinvoke printf, __separatorMsg cinvoke printf, __fmulMsg fild DWORD[ebp+8] ; S: A fild DWORD[ebp+4] ; S: B, A fimul st1 ; S: AB fistp [__output] cinvoke printf, __mulResultMsg, DWORD[ebp+8], DWORD[ebp+4], [__output] lea esp, [ebp-4] pop ebp ret For some reason the fimul st1(or fmul, fmulp) is giving me an error, why is that? I haven't been able to make it work in any way. |
|||
![]() |
|
gunblade 05 Apr 2012, 16:44
Did you remember to execute the finit instruction somewhere at the start of your code before you execute that subroutine? That could be the issue..
|
|||
![]() |
|
AsmGuru62 05 Apr 2012, 16:59
FMUL ST1 -- not FIMUL ST1.
ST1 is not Integer. Also, FMULP is better here, because when this function returns FPU will have ST0 in a non-empty state. It may cause exceptions later in code. A simple example would be to call that function in a loop for 8 times -- somewhere after that - the FPU will give an exception on load a value into ST0, because all 8 FPU registers will be busy with values. |
|||
![]() |
|
gunblade 05 Apr 2012, 17:15
Well spotted, didnt see the i
![]() |
|||
![]() |
|
gunblade 05 Apr 2012, 17:21
Ah, just tried it in my own code. You mean it doesnt assemble? fasm gives you an error? because it does for me. You cant do fimul st1, as AsmGuru62 says.. What you should use is just:
Code: fmulp No parameters.. that'll carry out st1 = st0*st1 then pop the stack Not sure if finit makes a difference, my code still seems to run whether i finit or not.. but I would do it to be safe.. If you REALLY wanted to specify parameter, then you have to specify both registers, such as: Code: fmulp st1,st0 |
|||
![]() |
|
Goto page Previous 1, 2, 3, 4, 5, 6, 7 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2023, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.
Website powered by rwasa.