My Goal is to redifine an existing label in the .data section of my Nasm Code.
The expected result shoud be that the existing memory label gets overwritten by the same procedure
The occuring errormessages are:
exp3.asm:230: error: comma, colon, decorator or end of line expected after operand
exp3.asm:191: ... from macro `var' defined here
exp3.asm:230: warning: character constant too long
exp3.asm:191: ... from macro `var' defined here
exp3.asm:230: error: parser: instruction expected
exp3.asm:195: ... from macro `var' defined here
exp3.asm:231: error: comma, colon, decorator or end of line expected after operand
exp3.asm:191: ... from macro `var' defined here
exp3.asm:231: error: symbol `test' redefined
exp3.asm:195: ... from macro `var' defined here
exp3.asm:231: error: parser: instruction expected
exp3.asm:195: ... from macro `var' defined here
Ive tried to rearange the word types, but it just complicated the problem instead of solving it.
The Required Macros:
%macro ifexis 3
push rax ; make room
mov rax, %1 ; platziere wert in Vergleichsregister
test rax, rax ; wenn werte gleich oder nicht leer
jz [%2] ; Gehe zu erfolg
jmp [%3] ; gehe zu fail
pop rax ; clear rax
%endmacro
Checks if the value exists by loading the Contents in to RAX and then testing it against eachother
%macro var 2
ifexis %1, %%overwrite, %%establish ;<--------------------------------------- Für gleiche labels muss eine lösung gefunden werden
%%overwrite: ;<---------------------------------------------------------------
mov db[%1], %2 ;<-------------------------------------------------------------
jmp %%end;<-------------------------------------------------------------------
%%establish:;<----------------------------------------------------------------
section .data
%1: db %2
;db 0
section .text
%%end:
%endmacro
Test code:
section .text
global _start
_start:
var test, "a"
var test, "b"
Any aditional sources for learning Assembler are welcome
Related
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
I'm trying to create dll using VS 2017.
The dll will have one proc: symbol_count.
It asks to enter the string and then set symbol what is needed to count.
.def file
LIBRARY name
EXPORTS
symbol_count
Code:
.586
.model flat, stdcall
option casemap: none
include C:\masm32\include\windows.inc
include C:\masm32\include\user32.inc
include C:\masm32\include\msvcrt.inc
includelib C:\masm32\lib\msvcrt.lib
includelib C:\masm32\lib\user32.lib
.data
msg_string db 'Enter string: ', 0
msg_symbol db 'Enter symbol: ', 0
result db 'Count = %d', 0
str_modifier db '%s', 0
sym_modifier db '%c', 0
.data
string db ?
symbol db ?
DllEntry PROC hInstDLL:DWORD, reason:DWORD, reserved:DWORD
mov eax, 1
ret
DllEntry ENDP
symbol_count PROC
invoke crt_printf, OFFSET msg_string
invoke crt_scanf, OFFSET str_modifier, OFFSET string
invoke crt_printf, OFFSET msg_symbol
invoke crt_scanf, OFFSET sym_modifier, OFFSET symbol
xor esi, esi
xor ecx, ecx
mov ebx, OFFSET string
mov ecx, eax
mov al, symbol
loop1: <------------------------------------------ A2108
cmp byte ptr [ebx + ecx], 0
je endloop <------------------------------ A2107
cmp al, byte ptr [ebx + ecx]
jne next <-------------------------------- A2107
inc esi
next: <------------------------------------------- A2108
inc ecx
jmp loop1 <------------------------------- A2107
endloop: <---------------------------------------- A2108
invoke crt_printf, OFFSET result, esi
ret
symbol_count ENDP
End DllEntry
Here is the list of error messages, what a compiler gives to me: (
in the code, I marked the places where the compiler swears)
A2108 use of register assumed to ERROR
A2108 use of register assumed to ERROR
A2108 use of register assumed to ERROR
A2107 cannot have implicit far jump or call to near label
A2107 cannot have implicit far jump or call to near label
A2107 cannot have implicit far jump or call to near label
procedure argument or local not referenced : hInstDLL } all this points
procedure argument or local not referenced : reason } to DllEntry ENDP
procedure argument or local not referenced : reserved }
"You put your code into the .data section which may or may not cause some of the errors. The last 3 should just be warnings as you don't use the arguments." – #Jester
Consider a nasm macro that is used to inject some assembly whenever it is called, in this case to test whether the passed argument is equal to 42:
%macro special_handler_if_42 1
cmp 42, %1
jne %%skip
; some additional assembly to handle the %1 == 42 case
push %1
push 42
call some_func
%%skip:
%endmacro
In the case it is equal we perform some additional action, otherwise we just continue with the code following the macro. So far, so good.
Now I want to write the macro in a way that's functionally identical, except that the "equals 42" case, which happens to be very rare, is moved "out of line", so that the fall-through (no jump) case is the default one, something like (not shown in macro form now):
cmp 42, rax
je equals_42
jump_back:
; the rest of the code that follows the macro
ret
; somewhere outside the current function
equals_42:
push rax
push 42
call some_func
jmp jump_back
This will be more efficient at execution time and also potentially conserve i-cache space. I'm not sure how to write a macro with a non-local effect like that. Ideas welcome.
If you don't mind splitting the macro into two macros, one performing the test and one handling the assertion, then you can use NASM's context stack.
I imagined a system of macros of the form assert_XXX that are all pretty similar and perform specific tests.
A single assertions_handler past the end of the function will generate any handler needed.
Since this system uses the context stack, you should be able to use it multiple times for different functions.
Basically, each assert_XXX function will push a context on the stack and the assertions_handler will consume them all.
assert_XXX will also define context local macros argX to pass its argument to the handler, so there is no need to hardcode anything.
BITS 64
%macro assert_not_equal 2
;Create and push a new context (The name is optional but goodpractice)
%push assert_equal_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
je %$handler
%$jump_back:
%endmacro
%macro assert_greater 2
%push assert_greater_ctx
%define %$arg1 %1
%define %$arg2 %2
cmp %1, %2
jbe %$handler
%$jump_back:
%endmacro
%macro assertions_handler 0
%rep 1000
%ifctx assert_equal_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc
jmp %$jump_back
%pop assert_equal_ctx
%elifctx assert_greater_ctx
%$handler:
push %$arg1
push %$arg2
call somefunc2
%pop assert_greater_ctx
%else
%exitrep
%endif
%endrep
%endmacro
;
;TEST TEST TEST TEST TEST TEST TEST TEST
;
assert_not_equal rax, 5
nop
nop
nop
assert_greater rax, 8
nop
nop
nop
ret
assertions_handler
;
; Handler functions
;
somefunc:
ret
somefunc2:
ret
The maximum number of assertions per function is set to 1000, you can increment it up to 262.
I have the following code:
%include "io.inc"
section .data
msg db 'Hello World...$'
section .text
global CMAIN
CMAIN:
;write your code here
mov ah,09
mov dx,OFFSET msg
int 21h
xor eax, eax
xor dx,dx
ret
and it gets the next error:
[19:28:32] Warning! Errors have occurred in the build:
C:/Users/user/AppData/Local/Temp/SASM/program.asm:12: error: comma, colon, decorator or end of line expected after operand
gcc.exe: error: C:/Users/user/AppData/Local/Temp/SASM/program.o: No such file or directory
What is the problem? i'm using sasm ide.
This is TASM/MASM syntax:
mov dx,OFFSET msg
When using NASM you'd simply write:
mov dx,msg
So I have a simple C program that loops through the args passed to main then returns:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for(i = 0; i < argc; ++i) {
fprintf(stdout, "%s\n", argv[i]);
}
return 0;
}
I wanted to see how gcc wrote out the assembly in NASM format. I was looking over the output in the .asm file and noticed that the syntax was TASM. Below is the make file and the output from gcc. Am I doing something wrong or is it that gcc does not output true NASM syntax?
all: main
main: main.o
ld -o main main.o
main.o : main.c
gcc -S -masm=intel -o main.asm main.c
nasm -f elf -g -F stabs main.asm -l main.lst
AND
.file "main.c"
.intel_syntax noprefix
.section .rodata
.LC0:
.string "%s\n"
.text
.globl main
.type main, #function
main:
push ebp
mov ebp, esp
and esp, -16
sub esp, 32
mov DWORD PTR [esp+28], 0
jmp .L2
.L3:
mov eax, DWORD PTR [esp+28]
sal eax, 2
add eax, DWORD PTR [ebp+12]
mov ecx, DWORD PTR [eax]
mov edx, OFFSET FLAT:.LC0
mov eax, DWORD PTR stdout
mov DWORD PTR [esp+8], ecx
mov DWORD PTR [esp+4], edx
mov DWORD PTR [esp], eax
call fprintf
add DWORD PTR [esp+28], 1
.L2:
mov eax, DWORD PTR [esp+28]
cmp eax, DWORD PTR [ebp+8]
jl .L3
mov eax, 0
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.5.1 20100924 (Red Hat 4.5.1-4)"
.section .note.GNU-stack,"",#progbits
The errors on the command line are:
[mehoggan#fedora sandbox-print_args]$ make
gcc -S -masm=intel -o main.asm main.c
nasm -f elf -g -F stabs main.asm -l main.lst
main.asm:1: error: attempt to define a local label before any non-local labels
main.asm:1: error: parser: instruction expected
main.asm:2: error: attempt to define a local label before any non-local labels
main.asm:2: error: parser: instruction expected
main.asm:3: error: attempt to define a local label before any non-local labels
main.asm:3: error: parser: instruction expected
main.asm:4: error: attempt to define a local label before any non-local labels
main.asm:5: error: attempt to define a local label before any non-local labels
main.asm:5: error: parser: instruction expected
main.asm:6: error: attempt to define a local label before any non-local labels
main.asm:7: error: attempt to define a local label before any non-local labels
main.asm:7: error: parser: instruction expected
main.asm:8: error: attempt to define a local label before any non-local labels
main.asm:8: error: parser: instruction expected
main.asm:14: error: comma, colon or end of line expected
main.asm:17: error: comma, colon or end of line expected
main.asm:19: error: comma, colon or end of line expected
main.asm:20: error: comma, colon or end of line expected
main.asm:21: error: comma, colon or end of line expected
main.asm:22: error: comma, colon or end of line expected
main.asm:23: error: comma, colon or end of line expected
main.asm:24: error: comma, colon or end of line expected
main.asm:25: error: comma, colon or end of line expected
main.asm:27: error: comma, colon or end of line expected
main.asm:29: error: comma, colon or end of line expected
main.asm:30: error: comma, colon or end of line expected
main.asm:35: error: parser: instruction expected
main.asm:36: error: parser: instruction expected
main.asm:37: error: parser: instruction expected
make: *** [main.o] Error 1
What lead me to believe that this is TASM syntax was information posted at this link:
http://rs1.szif.hu/~tomcat/win32/intro.txt
TASM coders usually have lexical difficulties with NASM because it
lacks the "ptr" keyword used extensively in TASM.
TASM uses this:
mov al, byte ptr [ds:si] or mov ax, word ptr [ds:si] or mov eax,
dword ptr [ds:si]
For NASM This simply translates into:
mov al, byte [ds:si] or mov ax, word [ds:si] or mov eax, dword
[ds:si]
NASM allows these size keywords in many places, and thus gives you a
lot of control over the generated opcodes in a unifrom way, for
example These are all valid:
push dword 123 jmp [ds: word 1234] ; these both specify the size
of the offset jmp [ds: dword 1234] ; for tricky code when
interfacing 32bit and
; 16bit segments
it can get pretty hairy, but the important thing to remember is you
can have all the control you need, when you want it.
Intel syntax means Intel syntax, not NASM syntax. MASM and TASM syntaxes are based on Intel Syntax, NASM syntax gets inspiration from Intel syntax, but it is different.
What gcc outputs is actually gas syntax using Intel syntax for individual instructions, (Assembler directives, labels et al. use gas-specific syntax)