NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: Ferran on August 19, 2020, 11:07:58 AM
-
Hello everybody:
I'm still a newbie learning the assembly code. I'm trying to compile, linking and execute an script from capter 9.4 on assembly64.pdf (http://assembly64.pdf) but i can't.
the program named array4.asm is this:
; ***********************************************************************************
; array4.asm
; Exemple to learn how to use the stack to reverse a list of quadwords in
;place.
; Compile with nasm -f elf64 array4.asm
; Link with ld -o array4 array4.o
; Run with ./array4
;
; Source: assembly64.pdf (version 1.1.40)
; Author: Ed Jorgensen Ph.D.
; ************************************************************************************
section .data
lst dq 121, 122, 123, 124, 125
len dq 5
; ************************************************************************************
section .text
global _start
_start:
; loop to put the numbers on stack
mov rcx, qword len
mov rbx, lst
mov r12, 0
mov rax, 0
pushloop:
push qword [rbx+r12*8]
inc r12
loop pushloop
; ----
; All numbers are on stack (in reverse order).
; Look to get them back off. Put them back into
; the original list...
mov rcx, qword [len]
mov rbx, lst
mov r12, 0
poploop:
pop rax
mov qword [rbx+r12*8], rax
inc r12
loop poploop
; ----
; Done. Terminate program.
exit:
mov rax, 60
mov rdi, 0
syscall
Compiled with nasm -f elf64 array4.asm
Linked with ld -o array4 array4.o
Executing with ./array4
But when I tries to link the object file the system shows a segment error of memory, but I'm not able to locate the problem so I need help to fix it. I hope you can.
Thank you in advance.
-
This is where the error is:
mov rcx, qword len
But I recomend the following modifications (See NOTE: at comments):
; ***********************************************************************************
; array5.asm
; Exemple to learn how to use the stack to reverse a list of quadwords in place.
; Compile with nasm -f elf64 array4.asm
; Link with ld -o array4 array4.o
; Run with ./array4
;
; Source: assembly64.pdf (verdion 1.1.40)
; Author: Ed Jorgensen Ph.D.
; ************************************************************************************
section .data
lst: dq 121, 122, 123, 124, 125
; NOTE: Don't need to allocate memory to store lst array length.
len equ (($ - lst) / 8)
; ************************************************************************************
section .text
global _start
_start:
; loop to put the numbers on stack
;
; NOTE: When you're dealing with values less than 2³² you can use
; the lower 32 bits portion of R?? register. The upper 32 will be
; automaticaly zeroed.
; I prefeer to load effective addresses with LEA, instead of MOV.
; To zero a register, XOR is preferable (smaller instruction).
mov ecx, len
lea rbx, [lst]
mov rdx, rbx ; We'll use RDX below.
xor edi,edi ; Using EDI instead or R12 to create smaller instructions.
xor eax,eax
; NOTE: Prefeer NOT to use INC/DEC and LOOP. Use ADD/SUB and DEC ECX/JNZ, instead.
; They are faster.
; Use 'local' labels if you don't intend to export them to the linker.
.pushloop:
push qword [rbx+rdi*8]
add rdi,1
dec ecx
jnz .pushloop
; ----
; All numbers are on stack (in reverse order).
; Look to get them back off. Put them back into
; the original list...
mov ecx, len
xor edi, edi
.poploop:
pop rax
mov [rdx+rdi*8], rax ; NOTE: Using RDX insead of RBX here.
add rdi,1
dec ecx
jnz .poploop
; ----
; Done. Terminate program.
mov eax, 60
xor edi,edi
syscall
-
@federicopissarra it works fine ! No more segment fault.
Another related question: How I can to print the current array's values ?
I tried this
.poploop:
pop rax
mov [rdx+rdi*8], rax ; NOTE: Using RDX insead of RBX here.
;Here we should print the current array value:
mov rdx, len ; Lenght of de value
mov rcx, [rdx+rdi*8] ; Let's put the current array value into buffer
mov rbx, 1 ; 1 = stdout
mov rax, 1 ; 1 = sys_write system call
add rdi,1
dec ecx
jnz .poploop
Certanly, my idea don't works. What can i do there ?
-
Another related question: How I can to print the current array's values ?
You'll need to implement something like this, in asm:
#include <stdlib.h>
void printvalue( long long v )
{
int sign;
char buffer[24];
unsigned int size;
char *p;
sign = v < 0;
size = 0;
p = buffer + sizeof buffer - 1;
do
{
*p-- = abs( v % 10 ) + '0';
v /= 10;
size++;
} while ( v );
if ( sign )
{
*p-- = '-';
size++;
}
++p;
sys_write( 1, p, size );
}
-
Not easy for me to implement with asm this... but i'll try it.
Thank you very much for your help.
-
@federicopissarra
I search a possible solution to print the values but i blundered trying to implement it into the program. I decided to call printf imiplemented for ubuntu / linux mint (my distribution).
first I declaring the external command at the top of program
extern printf
and after we call printf with its arguments (values of the array) while the loop gets out them.
; ----
; All numbers are on stack (in reverse order).
; Look to get them back off. Put them back into
; the original list...
mov ecx, len
xor edi, edi
.poploop:
pop rax
mov [rdx+rdi*8], rax
; ----------- fix this -----------
lea rsi, [rdx+rdi*8]
call printf wrt ..plt
;---------------------------------
add rdi,1
dec ecx
jnz .poploop
Surely it is necessary to give as an argument the format or length of the array but I do not know for sure. Also: I'm making a mess with the records and I don't know which one is useful to print the values.
I'm absolutely disoriented right now...
PD. Now we need to compile the program with nasm -f elf prog4.asm and link with gcc -no-pie progr4.o -o prog4
-
If you are willing to use an external funcion defined in the C Standard Library, which will link all inicialization/finalization code necessary, why bother to use assembly?
-
@federicopissarra : I wanted see if the console shows the array values, either its way...
Well... i'm blocked, i'm tired and i'm bored.
Finally i left below the last modification trying to print the values of the array. The famous fault words appears again 'Segment faults', etc.
; ***********************************************************************************
; array4.asm
; Exemple to learn how to use the stack to reverse a list of quadwords in place.
; (it was modified to display the values on console)
; Compile with nasm -f elf64 array4.asm
; Link with ld -o array4 array4.o
; Run with ./array4
;
; Source: assembly64.pdf (ver. 1.1.40)
; Author: Ed Jorgensen Ph.D.
; (Modified by the NASM Forum members - forum.nasm.us)
;
; ************************************************************************************
section .data
lst: dq 121, 122, 123, 124, 125
len equ (($ - lst) / 8)
; ************************************************************************************
section .text
global _start
_start:
mov ecx, len
lea rbx, [lst]
mov rdx, rbx
xor edi,edi
xor eax,eax
.pushloop:
push qword [rbx+rdi*8]
add rdi,1
dec ecx
jnz .pushloop
mov ecx, len
xor edi, edi
mov ecx, len
xor edi, edi
.poploop:
pop rax ;Estracts all values one to one (in its correct order)
;----- This part contains some error and it needs fixed -----
mov rcx, rax
mov rdx, 3
mov rbx, 1
mov rax, 1
syscall
; ---------------------------------------------------------------------------
add rdi, 1
dec ecx
jnz .poploop
.exit:
mov eax, 60
xor edi,edi
syscall
If someone finds a solution, it will make me very happy.
Good Luck.
-
Here, take a look:
; printlong.asm
bits 64
default rel
section .text
; Entry: RAX = n (signed long).
; Destroy: RAX, RBX, RCX, RDX, RSI, RDI, R8 and R9.
;
global printlong
printlong:
lea rsi,[rsp + 16] ; Points to the end of string.
sub rsp,40 ; allocate space on stack for string.
mov r8,rax ; Holds a copy of n to test for signal later.
xor ecx,ecx ; ECX will count how many chars in the buffer.
mov rbx,10 ; divisor on RBX.
mov r9,rax ; Need R9 in loop below (holds que quotient).
.loop:
mov rax,r9 ; Gets old quotient.
cqo ; Extends sign of RAX to RDX.
idiv rbx
mov r9,rax ; New quotient in R9.
test rdx,rdx ; Remainder is negative?
jns .notnegative ; No. don't negate.
neg rdx ; Yes. negate.
.notnegative:
add dl,'0' ; store '0' + remainder and decrease pointer.
mov [rsi],dl
dec rsi
inc ecx ; one more character on buffer.
test rax,rax ; Quotient is zero?
jnz .loop ; No. keep in loop.
mov edx,ecx ; Move size to EDX because of syscall.
test r8,r8 ; n is negative?
jns .skipsignal ; no. everything is ok.
mov byte [rsi],'-' ; yes. add '-' to buffer.
dec rsi
inc edx
.skipsignal:
inc rsi ; Points to the beginning of buffer.
mov eax,1 ; sys_write
mov edi,eax ; stdout
syscall
add rsp,40 ; deallocate space from stack.
ret
; test.asm
bits 64
default rel
section .rodata
lf: db `\n`
section .text
extern printlong
global _start
_start:
mov rax,-123
call printlong
; Prints final '\n'.
mov eax,1
mov edi,eax
lea rsi,[lf]
mov edx,eax
syscall
; exit(0).
xor edi,edi
mov eax,60
syscall
# Makefile
test: test.o printlong.o
ld -s -o $@ $^
test.o: test.asm
nasm -felf64 -o $@ $<
printlong.o: printlong.asm
nasm -felf64 -o $@ $<
.PHONY: clean
clean:
rm *.o
To test:
$ make
nasm -felf64 -o test.o test.asm
nasm -felf64 -o printlong.o printlong.asm
ld -s -o test test.o printlong.o
$ ./test
-123
$
[]s
Fred
-
@federicopissarra I agree all this effort and latests but my intention is to resume in 1 function with all I want. I need to call it from other program beetween several other options, etc.
But today I want to show i'm very happy, because finally I gain all I wanted with this project, Impossible without your help and more other people who agree too.
Look at it:
; ***********************************************************************************
; array6.asm
; Exemple to learn how to use the stack to reverse a list of quadwords in place.
; Compile with nasm -f elf64 array6.asm
; Link with gcc -no-pie array6.o -o array6
; Run with ./array6
;
; Source: assembly64.pdf (version 1.1.40)
; Author: Ed Jorgensen Ph.D.
;
; (Modified for the Nasm Forum members for print the array values)
; ************************************************************************************
segment .data
lst: dq 121, 122, -123, 124, 125
len equ (($ - lst) / 8)
a: dq 2
cnt: dq 0
fmt: dq "%lld ",10, 0
fmt_out: dq "The list is: ", 10, 0
lf: db `\n`
segment .bss
array resq 5
segment .text
global main
extern printf
main:
; Subrutine for load all list values on stack ( @federicopissarra)
push rbp
mov ecx, len
lea rbx, [lst]
mov rdx, rbx
xor edi,edi
xor eax,eax
mov rdi, 4 ; I did reverse the order of values of array with a trick
.pushloop:
push qword [rbx+rdi*8]
sub rdi, 1
dec ecx
jnz .pushloop
mov ecx, len
xor edi, edi
.poploop:
pop rax
mov [array+rdi*8], rax
add rdi,1
dec ecx
jnz .poploop
; Subrutine to print the values
.message:
mov rdi, fmt_out
call printf wrt ..plt
.printloop:
cmp rcx, 5
jz .printLineFeed
mov rax, [array+rcx*8]
inc rcx
mov [cnt], rcx
mov rdi, fmt
mov rsi, rax
call printf wrt ..plt
mov rcx, [cnt]
jmp .printloop
.printLineFeed:
mov rdi, lf
mov rsi, rax
call printf wrt ..plt
.end:
mov rax, 0
pop rbp
ret
Now we will can to see the values in normal order (fifo list ---> lifo stack ---> fifo array ---> display).
The last task will be to try to dispense with the C commands for printing and to use strictly those of the assembly language. But by the moment it isn't needed.
I need to enjoy it a little bit :)
-
Ok, @Ferran, keep in mind there is a problem using libc functions in a pure assembly code.
High level language compilers does more than meet the eye. In particular, C compilers add an initialization and an finalization code to all hosted codes. This is not embeded in the library itself, but in separate object files.
You were lucky because printf() worked well, but this is not always the case.
If your routine will be used inside a C program, ok... otherwise, avoid using C oriented libraries. Anyway, if you are willing to use a C function in your pure assembly code, why bother? Why not develop entirely in C?
-
I don't think I will have problems because I only need replay the model of this program. I'll tell you about it:
I have a project to create a very elementary and personalized programming language that is written in a .txt file. Each line of this file is read from a C file and then it is written inside a .asm file by means of fprintf() instructions. C works like an interpreter. E.g.:
if ( strcmp(token, "data") == 0 ) {
fprintf(myfileasm, "section \t .data \n");
}
There will not be assembly code running as such embedded on C, only text lines lwritten in an .asm file. Once finished then I compile and link the .asm as always.
Anyway I will continue trying to eradicate the "printf" of this program turning it into pure assembly code.
-
Anyway I will continue trying to eradicate the "printf" of this program turning it into pure assembly code.
I suggest you do the other way around. To create your parser/translator in C language instead of assembly. You'll need do code complex functions like binary trees to deal with expressions evaluations, for example, and to do this in ASM can be challenging.
Leave assembly to those funcions needing a boost of performance when you can't do it in C. Well... that's my advice.
-
Fred:
Here is a sample of a program named sum.txt wrote in my language. It sums to 2 numbers (currently is in 32 bits):
; ---- Section .data ---- ;
data:
integerB Number1=12345 ; This is an integer 'db'
integerB Number2=23456 ; This is another 'db'
string Message="The result is: " ; This is another 'db' (string) finished with ,0
stringLF Result=" " ; This is an empty field (5 blank spaces to fill) finished with 10, 0
; ---- Section text + global _start + _start lines: ---- ;
start:
sum Result=(Number1+Number2) ; subrutine that sums 2 numbers into Resultat
show (Message) ; sys_write of Message
show (Result) ; sys_write of Result
exit ; sys_exit
Once I proces with C this creates this sum.asm:
section .data
Number1 db '12345'
len_Number1 equ $ - Number1
Number2 db '23456'
len_Number2 equ $ - Number2
Message db "The result is: ", 0h
len_Message equ $ - Message
Result db " ", 0Ah, 0h
len_Result equ $ - Result
section .text
global _start
_start:
mov esi, 4
mov ecx, 5
clc
add_loop:
mov al, [Number1 + esi]
adc al, [Number2 + esi]
aaa
pushf
or al, 30h
popf
mov [Result + esi], al
dec esi
loop add_loop
mov edx, len_Message
mov ecx, Message
mov ebx, 1
mov eax, 4
int 80h
mov edx, len_Result
mov ecx, Result
mov ebx, 1
mov eax, 4
int 80h
mov ebx, 0
mov eax, 1
int 80h
By the moment nothing happens. It is only an .asm code more. After i will need to compile and link to see the magic.
# ./builder sum.txt
# nasm -f elf sum.asm
# ld -m elf_i386 sum.o -o sum
# ./sum
The result is: 35801
I am very proud to have reached to this point without problems ;D That's why it was important for me to move towards the integration of the arrays in the builder, and so on...
Really doing this serves me to learn more and better every day the assembly code, the architectures, the syntax, etc. I am going to consider your advice, but I want to see up to where all this takes me because I see it as a very interesting challenge. If I cannot continue with this then I will change of project as you say.