Why does this code not retrieve a valid file handle? - windows

Complete source:
SECTION .data ; initialized data
SEEK_SET dd 0;
SEEK_CUR dd 1;
SEEK_END dd 2;
fname: db "d:\asmplus\tsources\s1.txt", 0
fread: db "r", 0
mopf: db "open", 0
mskf: db "seek", 0
mcld: db "[FILE] call [%s]: %d", 10, 0
mcls: db "[FILE] call [%s]: %s", 10, 0
merr: db "[FILE] error opening %s", 10, 0
mret: db "[FILE] ret [%s]: %d", 10, 0
SECTION .text ; code
extern _fopen
extern _fseek
extern _printf
global _main
_main:
; stash base stack pointer
push ebp
mov ebp, esp
push DWORD fname
push DWORD mopf
push DWORD mcls
call _printf
add esp, 12
; open file
push DWORD fread
push DWORD fname
call _fopen
add esp, 8
mov [fh], eax
; output result
push DWORD [fh]
push DWORD mopf
push DWORD mret
call _printf
add esp, 12
push DWORD [fh]
push DWORD mskf
push DWORD mcld
call _printf
add esp, 12
; C:
; fseek(fp, 0L, SEEK_END); ; set up constants: SEEK_END, SEEK_SET, etc.
push DWORD SEEK_END
push DWORD 0
push DWORD [fh] ; file handle
call _fseek ; ret [eax]: 0 okay; otherwise nz
add esp, 12 ; reset stack pointer
; output result
push DWORD eax
push DWORD mskf
push DWORD mret
call _printf
add esp, 12
;; NEXT: sz = ftell(fp); ; result to eax
.done:
; restore base stack pointer
mov esp, ebp
pop ebp
ret
SECTION .bss ; uninitialized data
fh: resd 1
Output when provided a valid file name:
[FILE] call [open]: d:\asmplus\tsources\s1.txt
[FILE] ret [open]: 2002397536
[FILE] call [seek]: 2002397536
[FILE] ret [seek]: -1
The 2nd & 3rd lines should display a file handle. What I see does not look right and would be why the seek return is -1. What am I doing wrong to open the file?

Related

Why NASM : Segmentation Fault 11 in macOS?

I am studying NASM on MacOS.
I'm trying to implement a single line spacing using a function, but I have a problem.
SYS_EXIT equ 0x1
SYS_READ equ 0x3
SYS_WRITE equ 0x4
STDIN equ 0x1
STDOUT equ 0x2
segment .data
Msg_Line db " ", 0xA, 0x0
Len_Line equ $ - Msg_Line
Msg_FirstPrompt db "Enter a Digit : "
Len_FirstPrompt equ $ - Msg_FirstPrompt
Msg_SecondPrompt db "Please Enter a Second Digit : "
Len_SecondPrompt equ $ - Msg_SecondPrompt
Msg_ThirdPrompt db "The Sum is : "
Len_ThirdPrompt equ $ - Msg_ThirdPrompt
segment .bss
Bss_FirstNumber resb 2
Bss_SecondNumber resb 2
Bss_Result resb 1
section .text
global EntryPoint
Endl:
push dword eax
push dword Len_Line
push dword Msg_Line
push dword STDOUT
sub esp, 0x4
mov eax, SYS_WRITE
int 0x80
pop eax
ret 0x4
EntryPoint:
; Print First Prompt
push dword Len_FirstPrompt
push dword Msg_FirstPrompt
push dword STDOUT
sub esp, 0x4
mov eax, SYS_WRITE
int 0x80
; Get Digit
push dword 2
push dword Bss_FirstNumber
push dword STDIN
sub esp, 0x4
mov eax, SYS_READ
int 0x80
; Print Second Prompt
push dword Len_SecondPrompt
push dword Msg_SecondPrompt
push dword STDOUT
sub esp, 0x4
mov eax, SYS_WRITE
int 0x80
; Get Second Digit
push dword 2
push dword Bss_SecondNumber
push dword STDIN
sub esp, 0x4
mov eax, SYS_READ
int 0x80
; +operator use
mov eax, [Bss_FirstNumber]
sub eax, '0'
mov ebx, [Bss_SecondNumber]
sub ebx, '0'
add eax, ebx
add eax, '0'
mov [Bss_Result], eax
; Print Result Prompt
push dword Len_ThirdPrompt
push dword Msg_ThirdPrompt
push dword STDOUT
sub esp, 0x4
mov eax, SYS_WRITE
int 0x80
; Print Result
push dword 1
push dword Bss_Result
push dword STDOUT
sub esp, 0x4
mov eax, SYS_WRITE
int 0x80
sub esp, 0x4
call Endl
;push dword Len_Line
;push dword Msg_Line
;push dword STDOUT
;sub esp, 0x4
;mov eax, SYS_WRITE
;int 0x80
; Exit Program
sub esp, 0x4
mov eax, SYS_EXIT
int 0x80
Result :
Enter a Digit : 3
Please Enter a Second Digit : 2
The Sum is : 5
Segmentation fault: 11
It works fine if you just write it without calling it as a function.
Why do I get an error if I implement it as a function?

Value of unused variable changing after subroutine call - Assembly

I am pretty new to assembly that I'm learning from the last 7 hours (It's an early peek into the courses I had in the next semester starting next month). I read some online tutorials, and the nasm manual and started to port a C program to nasm, just for learning.
int fact(int n)
{
return (n < 0) ? 1 : n * fact(n - 1);
}
I then started to port it to assembly, and had this as my solution:
fact:
; int fact(int n)
cmp dword ebx, 0 ; n == 0
je .yes
.no:
push ebx ; save ebx in stack
sub ebx, dword 1 ; sub 1 from ebx. (n - 1)
call fact ; call fact recursively
pop ebx ; get back the ebx from stack
imul eax, ebx ; eax *= ebx; eax == fact(n - 1)
ret
.yes:
mov eax, dword 1 ; store 1 in eax to return it
ret
I take in a DWORD (int I suppose) in the ebx register and return the value in the eax register. As you can see I am not at all using the variable i that I have declared in the .bss section. My variables are like this:
section .bss
; int i, f
i resb 2
f resb 2
It's 2 bytes for an int right? Okay then I'm prompting the user in the _main, getting the input with _scanf and then calling the function. Other than this and calling the function, I have no other code that changes the value of i variable.
mov ebx, dword [i] ; check for validity of the factorial value
cmp dword ebx, 0
jnl .no
.yes:
push em ; print error message and exit
call _printf
add esp, 4
ret
.no:
push dword 0 ; print the result and exit
push dword [i]
push rm
call _printf
add esp, 12
call fact ; call the fact function
mov dword [f], eax
push dword [f] ; print the result and exit
push dword [i]
push rm
call _printf
add esp, 12
ret
I don't see where I'm modifying the value of i variable, on first print before the call to fact it is indeed the same value entered by the user, but after calling the function, in the later print, it is printing some garbage value, as the following output:
E:\ASM> factorial
Enter a number: 5
The factorial of 5 is 0The factorial of 7864325 is 120
E:\ASM>
Any clues? My complete source code is in this gist: https://gist.github.com/sriharshachilakapati/70049a778e12d8edd9c7acf6c2d44c33

Open and write to file in assembly on mac

I'm learning 32 bit assembly on mac, and I've have been trying to write to a file on my desktop. I used this code:
global _start
section .data
path: db "/Users/jackliu/Desktop/test.txt",0
string: db "hello",0
.len: equ $ - string
section .text
_start:
mov eax, 5
push dword 2
push dword path
sub esp, 8
int 0x80
add esp, 16
mov ebx, eax
mov eax, 4
push dword string.len
push dword string
push dword ebx
sub esp, 4
int 0x80
add esp, 16
mov eax, 1
push 0
sub esp, 12
int 0x80
The file is empty and it already exists on my desktop. After running it, it doesn't change the file at all.
Is there anything wrong with my code?
On MAC OS int 0x80 open system call is:
5 AUE_OPEN_RWTC ALL { int open(user_addr_t path, int flags, int mode); }
Your code passes 2 parameters:
mov eax, 5 ; Open system call = 5
push dword 2 ; Read/Write flag
push dword path ; Path
sub esp, 8 ; Alignment
int 0x80
Since you are opening an existing file specify a mode of 0 for the third parameter. Your code could look like this:
mov eax, 5 ; Open system call = 5
push dword 0 ; Mode = 0
push dword 2 ; Read/Write flag
push dword path ; Path
sub esp, 4 ; Reserved space for system call
int 0x80

Why is printf defined locally as opposed to getchar, which is defined externally?

When using assembly language with MASM (x86 architecture), one can make use of the standard C functions by including libraries. For example: printf and getchar.
When compiling with Asembly With Source Code/FAs in Visual Studio and inspecting the resulting assembly file I stumbled upon the following:
PUBLIC _printf
EXTRN __imp__getchar : PROC
_printf is declared PUBLIC and defined locally (inline within the same file, thus not defined externally in the library file), while _imp_getchar is defined externally
This is the resulting _printf definition the compiler generated while compiling in debug:
_TEXT SEGMENT
__ArgList$ = -20 ; size = 4
__Result$ = -8 ; size = 4
__Format$ = 8 ; size = 4
_printf PROC ; COMDAT
; 950 : {
push ebp
mov ebp, esp
sub esp, 216 ; 000000d8H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-216]
mov ecx, 54 ; 00000036H
mov eax, -858993460 ; ccccccccH
rep stosd
; 951 : int _Result;
; 952 : va_list _ArgList;
; 953 : __crt_va_start(_ArgList, _Format);
call ??$__vcrt_va_start_verify_argument_type#QBD##YAXXZ ; __vcrt_va_start_verify_argument_type<char const * const>
lea eax, DWORD PTR __Format$[ebp+4]
mov DWORD PTR __ArgList$[ebp], eax
; 954 : _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);
mov eax, DWORD PTR __ArgList$[ebp]
push eax
push 0
mov ecx, DWORD PTR __Format$[ebp]
push ecx
mov esi, esp
push 1
call DWORD PTR __imp____acrt_iob_func
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
push eax
call __vfprintf_l
add esp, 16 ; 00000010H
mov DWORD PTR __Result$[ebp], eax
; 955 : __crt_va_end(_ArgList);
mov DWORD PTR __ArgList$[ebp], 0
; 956 : return _Result;
mov eax, DWORD PTR __Result$[ebp]
; 957 : }
pop edi
pop esi
pop ebx
add esp, 216 ; 000000d8H
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
_printf ENDP
_TEXT ENDS
My question
Why is _printf defined locally as opposed to getchar, which is defined externally?
The code for printf is right there in your listing. If you remove the assembly, you get:
; 950 : {
; 951 : int _Result;
; 952 : va_list _ArgList;
; 953 : __crt_va_start(_ArgList, _Format);
; 954 : _Result = _vfprintf_l(stdout, _Format, NULL, _ArgList);
; 955 : __crt_va_end(_ArgList);
; 956 : return _Result;
; 957 : }
So, printf is an (inline?) function that calls _vfprintf_l, which does all the heavy work (and is probably used to implement other C library functions as well).

How to get window proc parameters?

I try to create the simplest WinAPI window using assembly NASM.
I have problem with Window Proc. Look at commented lines:
%macro API 2
import %1 %2
extern %1
%endmacro
API GetModuleHandleA, kernel32.dll
API LoadIconA,user32.dll
API LoadCursorA,user32.dll
API RegisterClassExA, user32.dll
API CreateWindowExA, user32.dll
API MessageBoxA, user32.dll
API SendMessageA, user32.dll
API DefWindowProcA, user32.dll
API ExitProcess, kernel32.dll
API GetMessageA, user32.dll
API DispatchMessageA, user32.dll
API TranslateMessage,user32.dll
API ShowWindow,user32.dll
API UpdateWindow,user32.dll
API GetCommandLineA,kernel32.dll
API PostQuitMessage,user32.dll
segment .data USE32
windowName db "Hello world!", 0
cmdLine dd 0
hWnd dd 0
hInst dd 0
hCursor dd 0
className db "moje_okno",0
blad db "Blad!!!",0
segment .bss
struc WNDCLASSEX
.sSize resb 4
.style resb 4
.wndProc resb 4
.clsExtra resb 4
.wndExtra resb 4
.hInstance resb 4
.hIcon resb 4
.hCursor resb 4
.background resb 4
.sMenuName resb 4
.sClassName resb 4
.hIconSm resb 4
endstruc
wndClass istruc WNDCLASSEX
iend
global ..start
segment .text USE32
..start:
push 0
call [GetModuleHandleA]
mov dword [hInst], eax ; application handle
push dword 0x00007f00 ; MAKEINTRESOURCE(32512)
push dword 0
call [LoadCursorA]
mov dword [hCursor], eax ; cursor handle
mov dword [wndClass + WNDCLASSEX.sSize], dword 48 ; struct size
mov dword [wndClass + WNDCLASSEX.style], dword 0 ; style
mov dword [wndClass + WNDCLASSEX.wndProc], wndproc ; window proc
mov dword [wndClass + WNDCLASSEX.clsExtra], dword 0
mov dword [wndClass + WNDCLASSEX.wndExtra], dword 0
mov eax, dword [hInst]
mov dword [wndClass + WNDCLASSEX.hInstance], eax ; handle
mov dword [wndClass + WNDCLASSEX.hIcon], dword 0
mov eax, dword [hCursor]
mov dword [wndClass + WNDCLASSEX.hCursor], eax
mov dword [wndClass + WNDCLASSEX.background], dword 0
mov dword [wndClass + WNDCLASSEX.sMenuName], dword 0
mov dword [wndClass + WNDCLASSEX.sClassName], className ; class name
mov dword [wndClass + WNDCLASSEX.hIconSm], dword 0
push wndClass
call [RegisterClassExA]
call near sprawdz_blad ; check return value of RegisterClassExA
push 0 ; param
push dword [hInst] ; handle
push 0 ;hMenu
push 0 ;parent
push 200 ;height
push 200 ;width
push 200 ;y
push 200 ;x
push 0 ;style
push className ;window name
push className ;window class
push 0 ;extended style
call [CreateWindowExA]
push eax
call near sprawdz_blad ;check return value of CreateWindowExA. RETURNS 0
push 0
call [ExitProcess]
wndproc:
; HERE I NEED ACCESS TO WINDOW PROC PARAMETERS: HWND, MSG, WPARAM, LPARAM
; I TRIED:
pop eax
pop ebx
pop ecx
pop edx
; BUT IT DOESN'T WORK
; THERE ARE NOT RIGHT VALUES IN THESE REGISTRIES
ret
box:
push 0
push blad
push blad
push 0
call [MessageBoxA]
ret
sprawdz_blad:
pop eax
cmp eax, 0
jne ok ; if function returns 0 everything is allright
push 0
push blad
push blad
push 0
call [MessageBoxA]
push 1
call [ExitProcess]
ok:
ret
I try to make it work for hours but I'm out of ideas.
Please help.
Greetings, Michal.
A called subroutine, wheether you call it yourself or it's called by Windows (like wndproc) has its return address as the first thing on the stack. You do NOT want to pop this! To access the parameters, you need to look farther up the stack. Try something like...
wndproc:
mov eax, [esp + 4]
mov ebx, [esp + 8]
; etc...
See if that helps...
Best,
Frank

Resources