Macros with File and Memory Management in Assemble Language
In Assembly macros is modular programming , file management concern with data input output standard and memory management convey the allocation of these data uses.
Macros use in Assembly
Macro is another way of ensuring modular programming in assembly language.It is a sequence of instructions, assigned by a name and could be used anywhere in the program.
- In NASM, macros are defined with %macro and %endmacro directives.
- The macro begins with the %macro directive and ends with the %endmacro directive.The Syntax for macro definition −
%macro macro_name number_of_params <macro body> %endmacro
Where, number_of_params specifies the number parameters, macro_name specifies the name of the macro. The macro is invoked by using the macro name along with the necessary parameters. When you need to use some sequence of instructions many times in a program. For example, a very common need for programs is to write a string of characters in the screen. For displaying a string of characters, you need the following sequence of instructions:
mov edx,len ;message length mov ecx,msg ;message to write mov ebx,1 ;file descriptor (stdout) mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel
In the above example of displaying a character string, the registers EAX, EBX, ECX and EDX have been used by the INT 80H function call. So, each time you need to display on screen, you need to save these registers on the stack, invoke INT 80H and then restore the original value of the registers from the stack. So, it could be useful to write two macros for saving and restoring data. Some instructions like IMUL, IDIV, INT, etc., need some of the information to be stored in some particular registers and even return values in some specific register(s). If the program was already using those registers for keeping important data, then the existing data from these registers should be saved in the stack and restored after the instruction is executed.
Example: There is an example shows defining and using macros:
; A macro with two parameters ; Implements the write system call %macro write_string 2 mov eax, 4 mov ebx, 1 mov ecx, %1 mov edx, %2 int 80h %endmacro section .text global _start ;must be declared for using gcc _start: ;tell linker entry point write_string msg1, len1 write_string msg2, len2 write_string msg3, len3 mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data msg1 db 'Hello, programmers!',0xA,0xD len1 equ $ - msg1 msg2 db 'Welcome to the world of,', 0xA,0xD len2 equ $- msg2 msg3 db 'Linux assembly programming! ' len3 equ $- msg3
OUTPUT:
Hello, programmers!
Welcome to the world of,
Linux assembly programming!
Assembly in File Management
The system considers any input or output data as stream of bytes. There are three standard file streams:
- Standard input (stdin),
- Standard output (stdout), and
- Standard error (stderr).
File Descriptor
A file descriptor is a 16-bit integer assigned to a file as a file id. So, when a new file is created or an existing file is opened, the file descriptor is used for accessing the file. File descriptor of the standard file streams – stdin, stdout and stderr are 0, 1 and 2, respectively.
File Pointer
A file pointer specifies the location for a subsequent read/write operation in the file in terms of bytes. Each file is considered as a sequence of bytes. Each open file is associated with a file pointer that specifies an offset in bytes, relative to the beginning of the file. When a file is opened, the file pointer is set to zero.
File Handling System Calls
The following table briefly describes the system calls related to file handling:
%eax Name %ebx %ecx %edx
2 sys_fork struct pt_regs – –
3 sys_read unsigned int char * size_t
4 sys_write unsigned int const char * size_t
5 sys_open const char * int int
6 sys_close unsigned int – –
8 sys_creat const char * int –
19 sys_lseek unsigned int off_t unsigned int
The steps required for using the system calls are same, as discussed earlier:
Put the system call number in the EAX register.
Store the arguments to the system call in the registers EBX, ECX, etc.
Call the relevant interrupt (80h).
The result is usually returned in the EAX register.
Creating and Opening a File
For creating and opening a file, perform the following tasks −
Put the system call sys_creat() number 8, in the EAX register.
Put the filename in the EBX register.
Put the file permissions in the ECX register.
The system call returns the file descriptor of the created file in the EAX register, in case of error, the error code is in the EAX register.
Opening an Existing File
For opening an existing file, perform the following tasks:
Put the system call sys_open() number 5, in the EAX register.
Put the filename in the EBX register.
Put the file access mode in the ECX register.
Put the file permissions in the EDX register.
The system call returns the file descriptor of the created file in the EAX register, in case of error, the error code is in the EAX register.
Among the file access modes, most commonly used are: read-only (0), write-only (1), and read-write (2).
Reading from a File
For reading from a file, perform the following tasks:
Put the system call sys_read() number 3, in the EAX register.
Put the file descriptor in the EBX register.
Put the pointer to the input buffer in the ECX register.
Put the buffer size, i.e., the number of bytes to read, in the EDX register.
The system call returns the number of bytes read in the EAX register, in case of error, the error code is in the EAX register.
Writing to a File
For writing to a file, perform the following tasks −
Put the system call sys_write() number 4, in the EAX register.
Put the file descriptor in the EBX register.
Put the pointer to the output buffer in the ECX register.
Put the buffer size, i.e., the number of bytes to write, in the EDX register.
The system call returns the actual number of bytes written in the EAX register, in case of error, the error code is in the EAX register.
Closing a File
For closing a file, perform the following tasks:
Put the system call sys_close() number 6, in the EAX register.
Put the file descriptor in the EBX register.
The system call returns, in case of error, the error code in the EAX register.
Updating a File
For updating a file, perform the following tasks :
Put the system call sys_lseek () number 19, in the EAX register.
Put the file descriptor in the EBX register.
Put the offset value in the ECX register.
Put the reference position for the offset in the EDX register.
The reference position could be:
Beginning of file – value 0
Current position – value 1
End of file – value 2
The system call returns, in case of error, the error code in the EAX register.
Example: The following program creates and opens a file named myfile.txt, and writes a text ‘Welcome to Tutorials Point’ in this file. Next, the program reads from the file and stores the data into a buffer named info. Lastly, it displays the text as stored in info.
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point ;create the file mov eax, 8 mov ebx, file_name mov ecx, 0777 ;read, write and execute by all int 0x80 ;call kernel mov [fd_out], eax ; write into the file mov edx,len ;number of bytes mov ecx, msg ;message to write mov ebx, [fd_out] ;file descriptor mov eax,4 ;system call number (sys_write) int 0x80 ;call kernel ; close the file mov eax, 6 mov ebx, [fd_out] ; write the message indicating end of file write mov eax, 4 mov ebx, 1 mov ecx, msg_done mov edx, len_done int 0x80 ;open the file for reading mov eax, 5 mov ebx, file_name mov ecx, 0 ;for read only access mov edx, 0777 ;read, write and execute by all int 0x80 mov [fd_in], eax ;read from file mov eax, 3 mov ebx, [fd_in] mov ecx, info mov edx, 26 int 0x80 ; close the file mov eax, 6 mov ebx, [fd_in] int 0x80 ; print the info mov eax, 4 mov ebx, 1 mov ecx, info mov edx, 26 int 0x80 mov eax,1 ;system call number (sys_exit) int 0x80 ;call kernel section .data file_name db 'myfile.txt' msg db 'Welcome to draftsbook' len equ $-msg msg_done db 'Written to file', 0xa len_done equ $-msg_done section .bss fd_out resb 1 fd_in resb 1 info resb 26
OUTPUT:
Written to file
Welcome to draftsbook
Memory Management
The sys_brk() system call is provided by the kernel, to allocate memory without the need of moving it later. This call allocates memory right behind the application image in the memory. This system function allows you to set the highest available address in the data section. This system call takes one parameter, which is the highest memory address needed to be set. This value is stored in the EBX register. In case of any error, sys_brk() returns -1 or returns the negative error code itself. The following example demonstrates dynamic memory allocation.
Example
The following program allocates 16kb of memory using the sys_brk() system call:
section .text global _start ;must be declared for using gcc _start: ;tell linker entry point mov eax, 45 ;sys_brk xor ebx, ebx int 80h add eax, 16384 ;number of bytes to be reserved mov ebx, eax mov eax, 45 ;sys_brk int 80h cmp eax, 0 jl exit ;exit, if error mov edi, eax ;EDI = highest available address sub edi, 4 ;pointing to the last DWORD mov ecx, 4096 ;number of DWORDs allocated xor eax, eax ;clear eax std ;backward rep stosd ;repete for entire allocated area cld ;put DF flag to normal state mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, len int 80h ;print a message exit: mov eax, 1 xor ebx, ebx int 80h section .data msg db "Allocated 16 kb of memory!", 10 len equ $ - msg
OUTPUT:
Allocated 16 kb of memory!