FASM: macro to display string - dos

I want to create macro in FASM, which could directly print string (int DOS) like this:
prints 'hey there!!!!'
I have written such code:
format MZ
use16
stack 0x100
entry _TEXT#16:_start
;
macro prints str
{
call #f
db str, 0x24
##:
pop dx
mov ah, 9
int 0x21
}
segment _DATA#16 use16
msg db 'hi!', 0xd, 0xa, 0x24
segment _TEXT#16 use16
_start:
push _DATA#16
pop ds
prints 'hi there))) !!!!'
prints 'me'
mov ax, 0x4c00
int 0x21
ret
The problem is: when I leave my _DATA#16 segment empty (without any variables) all is fine.
But when I define new variable in that segment some raw extra symbols begin to appear like this: http://board.flatassembler.net/files/err_758.png
So can you help me? where is my mistake?
Maybe I have chosen the wrong way to achieve that thing I want?
Help please....

As far as I understood it is because int 21h expects offset in _DATA#16 segment but not _CODE#16 segment. So, the easiest way - to use only one segment in program or just using .com files. Here is sample:
use16
org 0x100
macro prints [str*]
{
pusha
if str in <0xd, 0xa, 9>\
| str eqtype ''
call #f
db str, 0x24
##:
pop dx
else
mov dx, str
end if
mov ah, 9
int 0x21
popa
}
_start:
prints 0xd, 0xa, 9
prints 'hi!', 0xd, 0xa
mov ax, msg
prints ax, 0xd, 0xa
prints msg
int 0x20
ret
msg db 'hey there!', 0x24
It can accept strings directly, addresses of strings in registers and variables.
It can also handle 3 special characters - 0xd (CR), 0xa (LF) and 9 (TAB).
If I find the way to display string directly in multi-segment programs, I will post the answer.

Related

Hello world in NASM with LINK.EXE and WinAPI

I'm trying to get a simple Hello world program in NASM to run.
I want to print to the console without using C-Libraries, interfacing directly with WinAPI.
I am using the Visual Studio provided LINK.EXE for linking.
Here's my code so far:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleW
extern ExitProcess
section .text
_start:
; DWORD bytes;
mov rbp, rsp
sub rsp, byte 8
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-4]
push 0
call WriteConsoleW
; ExitProcess(0)
mov rcx, 0
call ExitProcess
ret
Which I assemble and link like this:
nasm -f win64 .\ASM.ASM
link /entry:_start /nodefaultlib /subsystem:console .\ASM.obj "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\kernel32.lib" "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.18362.0\um\x64\user32.lib"
However when I run the resulting .exe file, I get nothing.
Some things I tried so far are
Using the decorated names (like _GetStdHandle#4), which resulted in the linker complaining about unresolved references
Not trying to print anything and calling Sleep, which resulted in the process sleeping indefinitely
Exiting with a different return code, which once again did nothing
What am I doing wrong?
EDIT: Fixed calling convention
There are three problems with your revised code. The first is:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen: db $-message ; Length of the 'Hello world!' string
You defined messageLen to be a byte containing the length of the message and storing that value at the address of messageLen. You then do this:
mov r8, messageLen
That would move the address of label messageLen to r8. What you really should have done is define messageLen as an assembly time constant like this:
messageLen equ $-message ; Length of the 'Hello world!' string
The second problem is that you define the the string as a sequence of single byte characters:
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
There is nothing wrong with this, but to print them out you need to use the Ansi version of the function WriteConsole which is WriteConsoleA. Using WriteConsoleW printed the string as Unicode (UTF-16 on Windows 2000 and later, UTS-2 on NT4 and earlier versions of Windows).
The third problem is with regards to a mandatory 32 bytes of shadow space before the stack based parameter(s) are placed on the stack before making a function call. You also need to make sure the stack (RSP) is a 16-byte aligned value at the point of making a function call. These requirement can be found in the Microsoft 64-bit calling convention.
Code that would take this into account would look like this:
section .data
message: db 'Hello world!',10 ; 'Hello world!' plus a linefeed character
messageLen equ $-message ; Length of the 'Hello world!' string
global _start
extern GetStdHandle
extern WriteConsoleA
extern ExitProcess
section .text
_start:
; At _start the stack is 8 bytes misaligned because there is a return
; address to the MSVCRT runtime library on the stack.
; 8 bytes of temporary storage for `bytes`.
; allocate 32 bytes of stack for shadow space.
; 8 bytes for the 5th parameter of WriteConsole.
; An additional 8 bytes for padding to make RSP 16 byte aligned.
sub rsp, 8+8+8+32
; At this point RSP is aligned on a 16 byte boundary and all necessary
; space has been allocated.
; hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)
mov ecx, -11
call GetStdHandle
; WriteFile(hstdOut, message, length(message), &bytes, 0);
mov rcx, rax
mov rdx, message
mov r8, messageLen
lea r9, [rsp-16] ; Address for `bytes`
; RSP-17 through RSP-48 are the 32 bytes of shadow space
mov qword [rsp-56], 0 ; First stack parameter of WriteConsoleA function
call WriteConsoleA
; ExitProcess(0)
; mov rcx, 0
; call ExitProcess
; alternatively you can exit by setting RAX to 0
; and doing a ret
add rsp, 8+8+32+8 ; Restore the stack pointer.
xor eax, eax ; RAX = return value = 0
ret

Print hexa value in masm

I do a MapViewOfFile to get a pointer on the begin of my file, after that I want to print the value of it in hexa.
When I print it as string I get "MZ" which is the good value (the magic number) but I want it in hexa (5A4D).
I tried to format with %x in wsprintf but it doesn't work, I got 230000 as value..
EDIT the tried for %x:
.data
header_format db "The header is: %x",0
buffer db 256 dup(?) ; File data
.data?
pMemory DWORD ? ; Pointer to the data in the source file
getData:
;pMemory is the ptr which is correctly printed with %s
invoke wsprintf, ADDR buffer, ADDR header_format, [pMemory] ;
invoke MessageBox, NULL, Addr buffer, Addr header_test, MB_OK
Have you any suggestions ?
Thanks.
It finally works by using this solution :
push STD_OUTPUT_HANDLE
call GetStdHandle
mov eax, pMemory
push eax
print right$(uhex$(eax),2),13,10
pop eax
mov eax, pMemory
push eax
print right$(uhex$([eax]),2),13,10
pop eax

8086 ALP String Display

I have written a code for 8086 microprocessor for taking string from keyboard and displaying it as follows
Title Get the string from keyboard and display it
.model small
.stack 100h
.data
str1 db 'Enter String ','$'
str2 db 50 dup('$')
str3 db 0dh, 0ah, '$'
.code
main proc
mov ax,#data
mov ds,ax
mov ah,09h ; for displaying Enter String
lea dx,str1
int 21h
mov ah,0ah ; for taking i/p from keyboard
lea dx,str2
int 21h
mov ah,09h ; for displaying in new line
lea dx,str3
int 21h
mov ah,09h ; for displaying what you have entered
lea dx,str2+2
int 21h
int 21h
mov ah,4ch
int 21h
main endp
end main
I don't understand why we have to give effective address of the string as str+2 to print the inputted string back ? If simply lea dx, str2 is used no string is displayed.
Thanks in advance.
The first byte at STR2 should contain the maximum number of characters to read. The second byte should contain the number of characters already present. Because you initialized STR2 with 50 '$' characters and the ASCII value of '$' is 36 you effectively asked DOS to allow an input of 36 characters that are already there!
Better code str2 db 50,0,50 dup (0)
At the conclusion of this 'Buffered STDIN Input' the second byte will contain the number of characters that were read. I hope you see now why you need lea dx,str2+2. That's the address where the characters are.
Please note that with a first byte of 50 input is limited to 49 characters as DOS appends a terminating '$' character (Not included in the second byte).

Creating variables inside main's frame (Linux)

[SOLVED]
I'm trying to do my own assembly code to do what similar C code will do:
main()
{
scanf("%d",&integer_var); // here must be the address of the integer_var
printf("Your Value is:%d",integer_var);
}
Well this is in C, so I'm doing with NASM under linux with extern functions. scanf and printf and compile first with nasm and then with gcc.
Here's my code (is not right :D)
SECTION .text
argstr: db "%d",10,0
str: db "Your value is:%d",10,0
extern printf
extern scanf
SECTION .data
global main
main:
push ebp
mov esp,ebp
sub esp, 0x10 ;ok integer right?
mov [ebp-0x4],0x0 ;just put 0 number on our integer variable
mov eax,(ebp-0x4) ;here i don't know how to push the address of ebp-0x4
push ecx ;first push is last argument so here's our address to scanf
push argstr ;just the string format
call scanf ;call that to input something
;I have no idea how to do this
;but if i don't do this i get an error
;because the scanf won't clear the arguments on stack
;and what scanf can't return
pop edx ;maybe help here? but it works fine
pop edx
push [-0x4(ebp)] ;i want the value of our var :D
push str
call printf
pop edx ;clear the stack to avoid "segment fault" or something similar
pop edx
mov esp,ebp
pop ebp
ret ;the end :(
Compiler error:
a.asm:18: error: invalid operand type
a.asm:28: error: parser: expecting ]
Another thing: Do I need to align the stack on this case, by the way?
thanks guys ! :)
EDIT solved whole program!
well at least, I can print the variable with printf. scanf i will do later and then I will share here the last result:
SECTION .text
str: db "Value is:%d",10,0
extern printf
SECTION .data
global main
main:
push ebp ;the main function starts here.
mov ebp,esp
;
sub esp,4 ;we need 4bytes of space for the integer
and esp,0xfffffff0 ;align the stack
mov [esp-4], dword 0xff ;move the value 0xff to our var
mov eax,[esp-4] ;move our variable value to the eax
push eax ;second argument of printf
push str ;first argument of printf
call printf ;printf
;
add esp,16 ;this add to the stack pointer what we pushed basicly
mov ebp,esp ;if we don't do add 16 to esp it shows us
pop ebp ;a segment fault cuz ret doesnt pop saved ebp
ret ;of who whatever called this program :)
To load the address EBP-4 into EAX, use lea eax, [ebp-4]. (this is NOT the same as pushing the address.)
In order to push the value at memory location EBP-4, push dword [ebp-4] should work.
Then you need to specify operand size for one of your movs, too: mov [ebp-4], dword 0x0.
These will fix your current assembler errors, and make your program compile, but there are a few other errors in there that will probably prevent it from running.
Here's a working attempt that is close to yours:
;note the sections, the string literals are better in .rodata
;all code goes in .text
SECTION .rodata
;no newline after scanf string
argstr: db "%d",0
str: db "Your value is: %d",10,0
SECTION .text
extern printf
extern scanf
global main
main:
push ebp
mov ebp,esp ;move esp to ebp, NOT other way round!
sub esp, 4 ;4 bytes are enough for the local variable
;there are NO alignment requirements for this program
lea eax,[ebp-4]
push eax
push dword argstr
call scanf
add esp, 8 ;since we don't actually need the popped values
;we can increment esp instead of two pop edx
push dword [ebp-4]
push dword str
call printf
add esp, 8
mov esp,ebp
pop ebp
ret

Windows (x86) Assembly Append Null Terminator To Inputted String

I am currently trying to append a null terminator to an(a?) user inputted string:
.386
.model flat, stdcall
WriteFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
ReadFile PROTO STDCALL:DWORD, :PTR, :DWORD, :PTR DWORD, :PTR OVERLAPPED
GetStdHandle PROTO STDCALL:DWORD
.data
buff DB 100h DUP(?)
stdInHandle DWORD 0
bytesRead DWORD ?
.code
start:
;read string from stdin
INVOKE GetStdHandle, -10
MOV stdInHandle, eax
INVOKE ReadFile, stdInHandle, BYTE PTR[buff], 100, ADDR bytesRead, 0
;append null terminator on CR,LF
MOV eax, bytesRead
MOV edx, BYTE PTR[buff]
SUB eax, 2
AND BYTE PTR [eax+edx], 0
RET
END start
It refuses to assemble at MOV edx, BYTE PTR[buff] and gives me an error:
error: Invalid combination of opcode and operands (or wrong CPU setting).
So I'm assuming I cannot MOV the value of BYTE PTR[buff] into register edx. So I can't even begin to test if this method of trying to apply a NULL terminator to a string will even work.
My question is, what is wrong with the above code (should I use a different register instead of edx?)
What is the best way to apply a NULL terminator to the string?
You can't move a byte value into a dword sized register. You either need to use a byte sized register such as dl, or zero-extend it with movzx. As you are working with bytes, I suggest you go with the first option.
When I had to create methods for strings without using anything from good ole Irvine, I got the length of the string, incremented what the length returned as (you need to include an extra +1 for the null-terminator) by 1, and then added 0h to the end of the string where the pointer was where the counter is.
MOV EAX, SIZEOF lpSourceString + 1 ; Get the string length of string, add 1 to include null-terminator
INVOKE allocMem, EAX ; Allocate memory for a target to copy to
LEA ESI, [lpSourceString] ; put source address in ESI
MOV EDI, EAX ; copy the dest address to another register we can increment
MOV ECX, SIZEOF lpSourceString ; Set up loop counter
We have the size of the string. Now we can add the null-terminate to it. To do that, we need to make sure that we have a pointer looking at the end of the string. So if we have a method that returns a string in EAX, EAX needs to point to the start of the string (so we leave the allocMem unmodified, instead incrementing a copy in EDI). Let's say that we are putting characters in a string:
nextByte: ; Jump label, get the next byte in the string until ECX is 0
MOV DL, [ESI] ; Get the next character in the string
MOV [EDI], DL ; Store the byte at the position of ESI
INC ESI ; Move to next char in source
INC EDI ; INCrement EDI by 1
loop nextByte ; Re-loop to get next byte
MOV byte ptr[EDI], 0h ; Add null-terminator to end of string
; EAX holds a pointer to the start of the dynamically-allocated
; 0-terminated copy of lpSourceString
MOV requires the byte ptr size specifier because neither the [EDI] memory operand nor the 0 immediate operand would imply a size for the operation. The assembler wouldn't know if you meant a byte, word, or dword store.
I have this in my MASM, but I use a String_length stdcall method I had written due to a class requirement.
This is so common that the MASM32 runtime supplies this functionality as part of its runtime. All you need to do is include the relevant code:
include \masm32\include\masm32rt.inc
Then use the StripLF function as so:
invoke StripLF, addr buff
To fix your current problem (if you want to do it manually) , you need to move the address of buff to edx instead.
mov edx, offset buff

Resources