Logically, what I want to do is:
GLOBAL FRED
FRED EQU 5
in one module, and
EXTERN FRED
MOV ECX,FRED
in a second.
I'm aware that
first module
GLOBAL FRED
FRED: DD 5
second module
EXTERN FRED
MOV ECX,[FRED]
works perfectly happily, but what I'd really prefer is the first version.
I've tried
FRED EQU 5
FRED: EQU 5
%define FRED 5
%assign FRED 5
None worked - no error message, but the label is not exported. Only if FRED is an address does it co-operate.
So - is there any way of exporting a value from one module as a constant, not an address?
Nasm treats a dot character (".") as a legal character in symbol names.
You can use this to fake COM (Component Object Model) "Object Properties".
If you have 3 modules, each of which has a "width" variable, you can pull the following stunt:
;ButtonWidget
SECTION .data
global ButtonWidget.width, ButtonWidget.height
ButtonWidget:
.width dd 50
.height dd 10
;SelectWidget
SECTION .data
global SelectWidget.width, SelectWidget.height
SelectWidget:
.width dd 50
.height dd 100
;TextWidget
SECTION .data
global TextWidget.width, TextWidget.height
TextWidget:
.width dd 200
.height dd 10
In your main module,
;GUIapp
extern ButtonWidget.width, ButtonWidget.height
extern SelectWidget.width, SelectWidget.height
extern TextWidget.width, TextWidget.height
%macro MakeChildWindow 4
push %1
push %2
push %3
push %4
call makechildwindow
%endmacro
MakeChildWindow 10, 10, ButtonWidget.width, ButtonWidget.height
MakeChildWindow 10, 30, SelectWidget.width, SelectWidget.height
MakeChildWindow 10, 200, TextWidget.width, TextWidget.height
This technique has the advantage that the external variables can be fixed
or changeable and it is VERY readable.
Short answer: No.
You cannot use equ, define or assign for exporting because they do not show up in the compiled module as separate values. They only affect the preprocessor, so writing
FRED equ 5
mov ecx, FRED
actually compiles to
mov ecx, 5
Common practice is to use C-style header file that has all the constants defined and then just include the header file wherever needed.
fred.asm:
%ifndef FRED_ASM
%define FRED_ASM
%define FRED 5
; ... other constants ...
%endif
module.asm
%include "fred.asm"
mov ecx, FRED
If I understand you correctly, you want FRED to be defined somewhere and used by many modules/source files? Each module/source file, uses FRED and instead of changing the value in each source file and re-assembling each file, just change one instance of FRED and have it use everywhere? If this is the case, you can just plop the equates into a static library and link against it. This does not work with %define, only equ.
Try this:
libequates.asm
global FRED, JOHN
FRED equ 5
JOHN equ 6
makefile for libequates.asm (modify for you needs)
LIBRARY = libequates
all: $(LIBRARY) PostMake
$(LIBRARY): $(LIBRARY).o
ar -cr $(LIBRARY).a $(LIBRARY).o
strip --strip-unneeded $(LIBRARY).a
$(LIBRARY).o: $(LIBRARY).asm
nasm -f elf64 $(LIBRARY).asm -F dwarf
PostMake:
mkdir -p ~/projects/lib/
mv $(LIBRARY).a ~/projects/lib
Now to use and test if it works (I will use printf for simplicity):
externs.asm
extern FRED, JOHN, printf, exit
global start
section .data
fmtint db "%d", 10, 0
section .text
start:
mov rsi, FRED
mov rdi, fmtint
xor rax, rax
call printf
mov rsi, JOHN
mov rdi, fmtint
xor rax, rax
call printf
mov rdi, 0
call exit
makefile for externs.asm
APP = externs
all: $(APP) clean
$(APP): $(APP).o
ld -o $(APP) $(APP).o -entry start -L ~/projects/lib -lequates -lc -dynamic-linker /lib64/ld-linux-x86-64.so.2
$(APP).o: $(APP).asm
nasm -f elf64 $(APP).asm -F dwarf
clean:
rm $(APP).o
and output:
Now, you only need to change the equate value in one place, re-assemble only the static library and re-link your program/modules.
Related
GAS assembly knows about the .set-directive which can be combined with .rept to increment a label (variable) in a loop as in the example below:
pd:
.set SPAGE, 0
.rept 512
.quad SPAGE + 0x87 // PRESENT, R/W, USER, 2MB
.set SPAGE, SPAGE + 0x200000
.endr
How can I achieve something similar convenient in NASM? I know about TIMES directive, but this alone doesn't help me to achieve, what I want. Any ideas? The EQU-directive from NASM only allows assigning a value once. Hence, it will not solve my problem.
Indeed this is impossible to do with times directive due to the operand to TIMES is a critical expression, to repeat more than one line of code, or a complex macro, use the preprocessor %rep directive, take a look at this silly example:
global _start
section .text
_start:
mov rbx, 0
%assign i 0
%rep 5
mov rbx, [variable]
add rbx, i
mov [variable], rbx
%assign i i+1
%endrep
mov rax, 60 ; system call for exit
mov rdi, [variable]; value of 'variable' = 10
syscall
section .bss
variable: resb 1
Check the answer:
nasm -felf64 ass.asm && ld ass.o && ./a.out
echo $?
i am very new to assembly although i have lots of c and c++ experience.
my assembly code is supposed to print hello world like all first programs in a new language.
it prints out hello world but also prints out some extra text:
hello world!
.shstrtab.text.data
and here is my assembly program:
section .text
global _start ;for the linker
_start:
mov edx, length ; message length
mov ecx, message ; message to write
mov ebx, 1 ; file descriptor stdout
mov eax, 4 ; system call number
int 0x80 ; call kernel
mov eax, 1 ;system call number for sys_exit to exit program
int 0x80 ; call kernel
section .data
message db "hello world!"
length DD 10
if you know how to fix this also explain why is this happening.
thanks.
extra info: i am using nasm assembler with ld linker
so the problem is in adding length as it gives the address of length variable but not the value. the answer is to use move edx, [length]. thanks to Jester for pointing me that out
length equ $ - message | instead of length dd 10
I need to make a program that outputs a text file with an extension of .dna, I don't know if I can really do that, and if the text file will even be compatible with what I need to compare it afterwards. Anyway, I'm not really sure how to do this. I tried to look for some examples for NASM, but I didn't find much. I have an idea of what I'd need to do, but I just don't know what to call to generate a file.
Afterwards I'd need to write stuff into it, I'm not really sure on how to go on about that. Could anyone point me to some examples or something? I just need to see what is required to write my own thing.
Here's an example using system calls. Basically, you just open the file, write some data to it, then close and exit:
; nasm -f elf file.asm
; ld -m elf_i386 file.o
BITS 32
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
; a message we'll write to our file, same as the error message
hello: db 'Hello, file!', 10 ; the 10 is a newline at the end
hello_length: equ $ - hello
fd: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; // $ man 2 creat
; int fd = creat("file.txt", 0644); // the second argument is permission
; we get the syscall numbers from /usr/include/asm/unistd_32.h
mov eax, 8 ; creat
mov ebx, filename ; first argument
mov ecx, 644O ; the suffix O means Octal in nasm, like the leading 0 in C. see: http://www.nasm.us/doc/nasmdoc3.html
int 80h ; calls the kernel
cmp eax, -1 ; creat returns -1 on error
je error
mov [fd], eax ; the return value is in eax - the file descriptor
; now, we'll write something to the file
; // man 2 write
; write(fd, hello_pointer, hello_length)
mov eax, 4 ; write
mov ebx, [fd],
mov ecx, hello
mov edx, hello_length
int 80h
cmp eax, -1
; it should also close the file in a normal program upon write error
; since it is open, but meh, since we just terminate the kernel
; will clean up after us
je error
; and now we close the file
; // man 2 close
; close(fd);
mov eax, 6 ; close
mov ebx, [fd]
int 80h
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
The file will be called a.out if you copied my link command above. The -o option to ld changes that.
We can also call C functions, which helps if you need to write out things like numbers.
; nasm -f elf file.asm
; gcc -m32 file.o -nostdlib -lc # notice that we're using gcc to link, makes things a bit easier
; # the options are: -m32, 32 bit, -nostdlib, don't try to use the C lib cuz it will look for main()
; # and finally, -lc to add back some of the C standard library we want
BITS 32
; docs here: http://www.nasm.us/doc/nasmdoc6.html
; we declare the C functions as external symbols. the leading underscore is a C thing.
extern fopen
extern fprintf
extern fclose
section .data
; don't forget the 0 terminator if it akes a C string!
filename: db 'test.txt', 0
filemode: db 'wt', 0 ; the mode for fopen in C
format_string: db 'Hello with a number! %d is it.', 10, 0 ; new line and 0 terminator
; an error message to be printed with write(). The function doesn't
; use a C string so no need for a 0 here, but we do need length.
error_message: db 'Something went wrong.', 10 ; 10 == \n
; this next line means current location minus the error_message location
; which works out the message length.
; many of the system calls use pointer+length pairs instead of
; 0 terminated strings.
error_message_length: equ $ - error_message
fp: dd 0 ; this is like a global int variable in C
; global variables are generally a bad idea and there's other
; ways to do it, but for simplicity I'm using one here as the
; other ways are a bit more work in asm
section .text
global _start
_start:
; first, open or create the file. in C it would be:
; FILE* fp = fopen("text.txt", "wt");
; arguments for C functions are pushed on to the stack, right from left.
push filemode ; "wt"
push filename ; "text.txt"
call fopen
add esp, 8 ; we need to clean up our own stack. Since we pushed two four-byte items, we need to pop the 8 bytes back off. Alternatively, we could have called pop twice, but a single add instruction keeps our registers cleaner.
; the return value is in eax, store it in our fp variable after checking for errors
; in C: if(fp == NULL) goto error;
cmp eax, 0 ; check for null
je error
mov [fp], eax;
; call fprintf(fp, "format string with %d", 55);
; the 55 is just a random number to print
mov eax, 55
push eax ; all arguments are pushed, right to left. We want a 4 byte int equal to 55, so eax is it
push format_string
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fprintf
add esp, 12 ; 3 words this time to clean up
; fclose(fp);
mov eax, [fp] ; again using eax as an intermediate to store our 4 bytes as we push to the stack
push eax
call fclose
; the rest is unchanged from the above example
; and now close the program by calling exit(0);
mov eax, 1 ; exit
mov ebx, 0 ; return value
int 80h
error:
mov eax, 4 ; write
mov ebx, 1 ; write to stdout - file #1
mov ecx, error_message ; pointer to the string
mov edx, error_message_length ; length of the string
int 80h ; print it
mov eax, 1 ; exit
mov ebx, 1 ; return value
int 80h
There's a lot more that can be done here, like a few techniques to eliminate those global variables, or better error checking, or even writing a C style main() in assembly. But this should get you started in writing out a text file. Tip: Files are the same as writing to the screen, you just need to open/create them first!
BTW don't mix the system calls and the C library functions at the same time. The C library (fprintf etc) buffers data, the system calls don't. If you mix them, the data might end up written to the file in a surprising order.
The code is similar, but slightly different in 64 bit.
Finally, this same pattern can be used to translate almost any C code to asm - the C calling convention is the same with different functions, and the linux system call convention with the argument placement etc. follows a consistent pattern too.
Further reading:
http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl on the C calling convention
http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html on linux system calls
What is the purpose of EBP in the following code? is another SO answer I wrote up a while ago about local variables in asm - this will have hints as to one way to get rid of that global and describes how the C compile does it. (the other way to get rid of that global is to either keep the fd/fp in a register and push and pop it onto the stack when you need to free up the register for something else)
And the man pages referenced in the code for each function. From your linux prompt, do things like man 2 write or man 3 fprintf to see more. (System calls are in manual section 2 and C functions are in manual section 3).
I'm starting to learn Assembler and I'm working in Unix. I want to open a file and write 'Hello world' on it.
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
int 80h
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
But when I compile it, it doesn't do anything. What am I doing wrong?
When I open a file where does the file descriptor value return to?
This is x86 Linux (x86 is not the only assembly language, and Linux is not the only Unix!)...
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
The filename string requires a 0-byte terminator: filetoopen db 'hi.txt', 0
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
2 is the O_RDWR flag for the open syscall. If you want the file to be created if it doesn't already exist, you will need the O_CREAT flag as well; and if you specify O_CREAT, you need a third argument which is the permissions mode for the file. If you poke around in the C headers, you'll find that O_CREAT is defined as 0100 - beware of the leading zero: this is an octal constant! You can write octal constants in nasm using the o suffix.
So you need something like mov ecx, 0102o to get the right flags and mov edx, 0666o to set the permssions.
int 80h
The return code from a syscall is passed in eax. Here, this will be the file descriptor (if the open succeeded) or a small negative number, which is a negative errno code (e.g. -1 for EPERM). Note that the convention for returning error codes from a raw syscall is not quite the same as the C syscall wrappers (which generally return -1 and set errno in the case of an error)...
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
...so here you need to mov ebx, eax first (to save the open result before eax is overwritten) then mov eax, 4. (You might want to think about checking that the result was positive first, and handling the failure to open in some way if it isn't.)
mov ecx, textoutput
mov edx, lentext
Missing int 80h here.
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
Did you read the Linux Assembly HOWTO? It covers your question.
You can also compile some C code with gcc -S -fverbose-asm -O1 and look at the generated assembly. For example, with foo.c, run gcc -S -Wall -fverbose-asm -O1 foo.c (as a command in some terminal) then look (using some editor -perhaps GNU emacs) into the generated foo.s assembler file.
At last, I don't think it is worth bothering a lot about assembler. In 2020, a recent GCC compiler will surely generate better code than what you could write (if you invoke it with optimizations, at least -O2). See this draft report for more.
This is a x64 Linux sample
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit
It depends what assembler you are using and if you expect to be using the C runtime or not. In this case which appears to be the Hello World text example from rosettacode they are using nasm. Given you have a _start field you are not needing the C runtime so you assemble this to an elf object file and link it into a program:
nasm -felf hello.asm
ld hello.o -o hello
Now you can run the hello program.
A slightly more portable example that uses the C runtime to do the work rather than linux syscalls might look like the sample below. If you link this as described it can use printf to do the printing.
;;; helloworld.asm -
;;;
;;; NASM code for Windows using the C runtime library
;;;
;;; For windows - change printf to _printf and then:
;;; nasm -fwin32 helloworld.asm
;;; link -subsystem:console -out:helloworld.exe -nodefaultlib -entry:main
;;; helloworld.obj msvcrt.lib
;;; For gcc (linux, unix etc):
;;; nasm -felf helloworld.asm
;;; gcc -o helloworld helloworld.o
extern printf
section .data
message:
db 'Hello, World', 10, 0
section .text
global main
main:
push dword message ; push function parameters
call printf ; call C library function
add esp, 4 ; clean up the stack
mov eax, 0 ; exit code 0
ret
For information about file descriptors - read the open(2) manual page or look at wikipedia. It is how posix refers to an open i/o stream. In your case, stdout.
I want to program in NASM assembly language. I have NASM 2.07 and Borland C++ compiler 5.0 (bcc32). My OS is Windows 7. I do not know how to do input and output with NASM in Windows platform. Please can you help me?
The easiest way is to call the Win32 functions, accessible by linking the kernel32 libs (IIRC).
You can use the "C" functions "printf" and "scanf".
For doing that you need to declare it as "extern".
There is a simple example:
section .data
input_string db 0
format db "%s", 0
output_string1 db "type something", 10, 0 ; "type something\n"
output_string2 db "you wrote: %s", 0
extern _printf
extern _scanf
section .text
global _main
_main: ; int main()
push output_string1 ;
call _printf ; printf(string1);
add esp, 4 ;
push output_string1 ;
push format ;
call _scanf ; scanf(format, string1);
add esp, 8 ;
push input_string ;
push output_string2 ;
call _printf ; printf(output_string2, input_string);
add esp, 8 ;
xor eax, eax ; return 0;
ret ;