flat assembler
Message board for the users of flat assembler.
Index
> Windows > I have the assembler, now what? Goto page Previous 1, 2, 3, 4, 5, 6 Next |
Author |
|
revolution 29 Mar 2017, 04:17
C0deHer3tic wrote: I have a possible ridiculous query. Is it possible to use stand alone assembly code to print stdout, and get stdin? Code: proc printf_stdoutput c string,args locals buff rb 1028 endl invoke wvsprintf,addr buff,[string],addr args stdcall write_stdoutput,addr buff,eax ret endp proc write_stdoutput source,bytes local bytes_written:DWORD invoke GetStdHandle,STD_OUTPUT_HANDLE invoke WriteFile,eax,[source],[bytes],addr bytes_written,0 test eax,eax jz .done mov eax,[bytes_written] .done: ret endp |
|||
29 Mar 2017, 04:17 |
|
C0deHer3tic 29 Mar 2017, 05:42
Thank you Trinitek and revolution.
Now when told to see the C assembly code by gcc -S -o... I get this: Code: .file "test1.c" .comm number, 4, 2 .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "Enter a number:\11\0" .LC1: .ascii "%d\0" .LC2: .ascii "\12The number is %d!\12\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue call __main leaq .LC0(%rip), %rcx call printf leaq number(%rip), %rax movq %rax, %rdx leaq .LC1(%rip), %rcx call scanf leaq number(%rip), %rax movl (%rax), %eax movl %eax, %edx leaq .LC2(%rip), %rcx call printf movl $0, %eax addq $32, %rsp popq %rbp ret .seh_endproc .ident "GCC: (tdm64-2) 4.8.1" .def printf; .scl 2; .type 32; .endef .def scanf; .scl 2; .type 32; .endef From the file test1.c: Code: #include <stdio.h> int number; int main() { printf("Enter a number:\t"); scanf("%d",&number); printf("\nThe number is %d!\n",number); return 0; } So then I tried to do this: Code: format PE console entry start include 'win32a.inc' include 'dota.inc' ;holds my imports section '.data' readable writeable prompt db "Enter a number:",9,9,0 result db 10,"The number is %d!",1010b,0 number db "%d",0 num dd 3 section '.main' code readable start: push ebp mov esp, ebp sub esp, 32 lea ecx, [prompt] call [printf] lea eax, [num] mov eax, edx lea ecx, [number] call [scanf] lea eax, [number] mov eax,eax mov eax, edx lea ecx, [result] call [printf] mov eax, 0 add esp, 32 pop ebp ret Which crashes. What am I doing wrong? I tried to do the code exactly how it showed, and it failed, then I tried to change the registers from rsp to esp, rax, eax, etc. Now that you have provided me with something new to look at, Revolution, I will study that while I also try to figure out my errors. I appreciate everything from you ladies and gentlemen. - Pluggin away, C0deHer3tic _________________ - Just because something is taught one way, does not mean there is not a different way, possibly more efficient. - |
|||
29 Mar 2017, 05:42 |
|
Trinitek 29 Mar 2017, 05:52
AT&T syntax--the nightmare returns.
AT&T syntax swaps the left and right operands, so there's one of your problems, at least. Use the -masm=intel flag to get Intel syntax instead, which is what FASM uses. |
|||
29 Mar 2017, 05:52 |
|
C0deHer3tic 29 Mar 2017, 07:20
Okay, so now I put got this from the masm=intel switch:
Code: .file "test1.c" .intel_syntax noprefix .comm number, 4, 2 .def __main; .scl 2; .type 32; .endef .section .rdata,"dr" .LC0: .ascii "Enter a number:\11\0" .LC1: .ascii "%d\0" .LC2: .ascii "\12The number is %d!\12\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: push rbp .seh_pushreg rbp mov rbp, rsp .seh_setframe rbp, 0 sub rsp, 32 .seh_stackalloc 32 .seh_endprologue call __main lea rcx, .LC0[rip] call printf lea rax, number[rip] mov rdx, rax lea rcx, .LC1[rip] call scanf lea rax, number[rip] mov eax, DWORD PTR [rax] mov edx, eax lea rcx, .LC2[rip] call printf mov eax, 0 add rsp, 32 pop rbp ret .seh_endproc .ident "GCC: (tdm64-2) 4.8.1" .def printf; .scl 2; .type 32; .endef .def scanf; .scl 2; .type 32; .endef My assembly code is now: Code: format PE console entry start include 'win32a.inc' include 'dota.inc' ; imports section '.data' readable writeable prompt db "Enter a number:",9,9,0 ;LC0 result db 10,"The number is %d!",1010b,0 ;LC2 number db "%d",0 ;LC1 num dd 3 section '.main' code readable start: push ebp mov ebp, esp sub esp, 32 lea ecx, [prompt] call printf lea eax, [num] mov edx, eax lea ecx, [number] call scanf lea eax, [num] mov eax, [eax] mov edx, eax lea ecx, [result] call printf mov eax, 0 add esp, 32 pop ebp ret And this gets a blinking cursor, and then crashes. What is the issue? What am I not understanding, and how can I learn? _________________ - Just because something is taught one way, does not mean there is not a different way, possibly more efficient. - |
|||
29 Mar 2017, 07:20 |
|
Trinitek 29 Mar 2017, 07:27
Issue #2 is that you've swapped the 64-bit registers with their 32-bit counterparts, but you've forgotten about the different calling conventions in use here.
GCC compiled your code into a 64-bit binary. Remember that 64-bit uses the fastcall convention. Since your assembly is 32-bit, you need to be using the 32-bit stdcall convention. I have to agree, getting into calling conventions on day 1 probably wasn't a good idea. |
|||
29 Mar 2017, 07:27 |
|
C0deHer3tic 29 Mar 2017, 07:34
Where would you recommend I start?
I am open to any task. I am a curious learner, can you guide me? |
|||
29 Mar 2017, 07:34 |
|
Trinitek 29 Mar 2017, 07:52
Well, let's go ahead and solve your issue here.
The first three instructions sets up some stack space to put local variables. Since you don't have any local variables, you can remove these 5 instructions: Code: push ebp mov ebp, esp sub esp, 32 ; ... add esp, 32 pop ebp Code: push Hello call [printf] add esp, 4 ; <-- only for variable-parameter functions like printf |
|||
29 Mar 2017, 07:52 |
|
C0deHer3tic 29 Mar 2017, 08:12
Alright, this is what my assembly looks like now:
Code: format PE console entry start include 'win32a.inc' include 'dota.inc' section '.data' readable writeable prompt db "Enter a number:",9,9,0 result db 10,"The number is %d!",1010b,0 number db "%d",0 num dd ? ; changed this to not have a set variable. section '.main' code readable start: push prompt call [printf] push num mov eax, edx push number call [scanf] push number mov eax,eax mov eax, edx push result call [printf] mov eax, 0 ret And this is the output: Code: Enter a number: 5 The number is 4202534! I enter 5, and hit enter, it displays message and crashes. Slowly but surely. _________________ - Just because something is taught one way, does not mean there is not a different way, possibly more efficient. - |
|||
29 Mar 2017, 08:12 |
|
C0deHer3tic 29 Mar 2017, 08:26
My internet is down for my pc. I am on a phone.
I fixed the problem of the crashing. But that ridiculous number is showing me that basically scanf is not getting the number I entered correctly. Will keep on trying to get it though. _________________ - Just because something is taught one way, does not mean there is not a different way, possibly more efficient. - |
|||
29 Mar 2017, 08:26 |
|
ctl3d32 29 Mar 2017, 09:58
|
|||
29 Mar 2017, 09:58 |
|
Furs 29 Mar 2017, 10:58
system error wrote: That's because you're extemely mad at me for giving you some schooling on 64-bit programming. (btw about rax, shows how much of an airhead you are, most functions return a value in rax, and other functions use that value as first argument, plus rax is an extra register to use to pass parameters; this is what is called SUPERIOR DESIGN. I don't personally give a shit if YOU find it insignificant. It is objectively better as it avoids 1 mov instruction for many function calls and uses 1 more register as parameter, so go cry to your mommy for getting schooled -- on and lastly, optimizing the function CALL is much more important than the FUNCTION itself because 1 function is called at LEAST one time, but usually many MORE times than once; so placing the overhead into EACH call makes for more bloated code (callee cleans and other crap), less cache used, etc, dummy) If varargs are your argument, those are a complete joke on x64 calling convention. The amount of extra bloat you have to do in your function is unimaginable to handle that properly. (and you cried for one 'and' instruction to align the stack pointer, LOL!!) C0deHer3tic wrote: Alright, this is what my assembly looks like now: Code: section '.main' code readable start: push prompt call [printf] push num ; this is correct, this pushes the *address* of 'num' for scanf (which is what it expects) mov eax, edx ; this has no purpose at all (edx has unknown value to begin with) push number call [scanf] ; this will put the number into 'num' (num as an address, a pointer, you pushed above) ; push number ; this is the wrong part: you push 'number' which is the address (!) of the *string* "%d" above push dword [num] ; instead, push this: this pushes the 32-bit (dword) *value* found at *num* (address); remember, we passed 'num' (address) to scanf, and it stored it there mov eax,eax ; useless instruction? I'm asking so I get to understand why you do this it doesn't do anything mov eax, edx ; same as above, what is its purpose? 'edx' is unknown value after scanf, eax is scanf's return value before this push result call [printf] mov eax, 0 ret Of course, you also need to clean the stack, as shown above with 'add esp, 8' or 'pop <dummy register>', that's why it crashes. But at least now it should print ok. |
|||
29 Mar 2017, 10:58 |
|
system error 29 Mar 2017, 11:26
Furs wrote: Or maybe because in his opening post in this thread he said he is experienced with several languages and gave example in C, idiot. I didn't realize he was asking how to use C standard library functions like scanf because of that reason. Using that knowledge you must have given him such wonderful advice to do what he already knows from C, indeed. On the other hand, looks like he doesn't understand pointers in asm (see his latest attempt), so you can try to ridicule me all you want, at least I know I help him unlike you. Looks like you're still extremely mad at me for that schooling thing. Well, angry people don't get no love from me |
|||
29 Mar 2017, 11:26 |
|
Furs 29 Mar 2017, 11:38
revolution wrote: In any protected OS the zone below the stack is perfectly safe for user mode programs to use in regards to worrying about the OS clobbering it. The x86 CPU provides for 4 independent stack pointers, one for for each privilege level. But one does still need to be aware of certain things when using that stack zone, push and call will overwrite any data there. Quote: The 128-byte area beyond the location pointed to by rsp is considered to be reserved and shall not be modified by signal or interrupt handlers. Therefore, functions may use this area for temporary data that is not needed across function calls. In particular, leaf functions may use this area for their entire stack frame, rather than adjusting the stack pointer in the prologue and epilogue. This area is known as the red zone. It says this: There is no concept of "red zone" whatsoever [in Windows ABI]. In fact, the ABI explicitly states that the area beyond rsp is considered volatile and unsafe to use. The OS, debuggers or interrupt handlers may overwrite this area. @system error: You know your behavior is exactly that of a kid not getting his way in an argument, covering his ears while shouting the same thing over and over again, right? Sigh, oh dear. If a hypothetical design required Bubble Sort on a huge data set, and I were to complain about it (because it doesn't use Quick Sort for example), system error would proudly come and claim "just because you don't know how to use Bubble Sort doesn't mean it sucks!" Grasping at straws, aye. That's all you've been doing, if you look at it. (and my main complaint was *because* we are forced to use this ABI to interact with library functions -- i.e. it's a bad design (in terms of waste and bloat) that escalates now, and into the future, for every compliant call -- including calls that use AVX which have to realign the stack anyway so you gain absolutely *nothing* from 16-byte alignment for future code, PERIOD) |
|||
29 Mar 2017, 11:38 |
|
system error 29 Mar 2017, 11:54
revolution wrote: It is also of note that you can use the stack pointer (ESP/RSP) as a general purpose computing register without causing any problem to the OS. Your stack pointer can even be 0x0000, or any other value you want, and the OS won't crash. But at some point you need to recover the original value before doing calls or pushes and that will usually require some global variable (and that often also precludes multi-threading). That's actually the general wisdom of MS64 ABI. Your RSP isn't involved in any function 'stacking' until after the 5th arguments kicks in. It is giving an impression that as far as the first 4 arguments go, the stack is still as 'flat' as static memory area. For example, theoritically, you can point to a static data area using RSP and saves you yet another pre-entry overhead, if you don't use more than 4 arguments. Example; Code: section '.data' bla bla here: _rcx dq 0 _rdx dq 0 ... _r9 dq 0 rb 32 section '.code' bla bla main: mov rsp,here ;hijacking the RSP to point to static data sub rsp,0x20 push $+8 jmp [aWinAPI] add rsp,0x20 Looks quite hackish but I blame it on MS for creating an ABI which empowers people to be 'creative'. IMHO, it can pose serious security threats. This is even more threatening in C because unlike MS, RSP in C is 'linked' to C's internal processing while in MS it is 'allocated' instead. |
|||
29 Mar 2017, 11:54 |
|
revolution 29 Mar 2017, 12:19
There are problem with pointing ESP/ESP to data areas. Exception handlers might not be able to be entered because the OS checks if ESP/RSP is inside a valid stack area. Also you should make sure there is enough space on the stack for the API to do its work. It is not until the kernel is entered that a new stack is used.
Furs: In a protected OS the stack use is at your leisure. Other non-protected OSes might not use different stacks for interrupts. So in those OSes you could get into trouble. Remember that AMD and Intel don't only support Windows and Linux, they also need to cover all situations. |
|||
29 Mar 2017, 12:19 |
|
system error 29 Mar 2017, 12:31
revolution wrote: There are problem with pointing ESP/ESP to data areas. Exception handlers might not be able to be entered because the OS checks if ESP/RSP is inside a valid stack area. Also you should make sure there is enough space on the stack for the API to do its work. It is not until the kernel is entered that a new stack is used Well, it's just a theory though. But bad things can still happen when the first few API data is well-exposed in the user's code. |
|||
29 Mar 2017, 12:31 |
|
Furs 29 Mar 2017, 13:53
revolution wrote: Furs: In a protected OS the stack use is at your leisure. Other non-protected OSes might not use different stacks for interrupts. So in those OSes you could get into trouble. Remember that AMD and Intel don't only support Windows and Linux, they also need to cover all situations. |
|||
29 Mar 2017, 13:53 |
|
revolution 29 Mar 2017, 14:03
Well if MS really does use the user program stack for system things then they have have broken the protection guarantees of the OS. In protected OSes no user code should ever be able to see system data, or another program's data in any memory it can access. Also no user program should even be able to tell that it was interrupted (in theory). So if a user program can simply examine the stack area for changes then the OS is not a protected OS.
|
|||
29 Mar 2017, 14:03 |
|
Furs 29 Mar 2017, 14:06
Well I doubt it is system data that it sees. It could be just user data from e.g. exceptions or for debugging. I don't know if Windows has Signal Handlers like Linux -- I'm not too fond of that low level stuff... Here more detail it seems: http://stackoverflow.com/questions/36489049/is-the-stack-only-preserved-above-the-stack-pointer
Even if it doesn't today maybe it's just a spec thing so it's never done in the future when it might be used for something. Still "unsafe" to use area below esp/rsp (it also seems to be unsafe when it triggers a page fault, since apparently Linux (not sure about Windows) only allocates more stack pages if it is >= esp and probably < start_of_stack) |
|||
29 Mar 2017, 14:06 |
|
Goto page Previous 1, 2, 3, 4, 5, 6 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.