I've made a nasm procedure that calculates the eucledian distance between two vectors of a certain size.
This nasm function is called from a C file which get the result of the function. I've tested, and it works, the value returned is correct, I can print it withoud any problem.
My issue is when I try to print the result inside the nasm file.
This is the nasm code:
extern printf
%macro print_dist2 1
section .data
.str db %1,0 ; %1 is macro call first actual parameter
section .text
push dword [dist]
push dword .str
push dword fmt2
call printf
add esp, 12 ; pop stack 3 * 4 bytes
%endmacro
section .data
dist: dd 258
fmt2: db "%s, dist: %g",10,0 ; format string for printf
section .bss
section .text
global distanza
x equ 8
y equ 12
dim equ 16
ris equ 20
distanza:
; ------------------------------------------------------------
; Function entrance sequence
; ------------------------------------------------------------
push ebp
mov ebp, esp
push ebx
push esi
push edi
; ------------------------------------------------------------
; read the parameters from the current stack frame
; ------------------------------------------------------------
mov eax, [ebp+x] ; address of x
mov ebx, [ebp+y] ; address of y
mov ecx, [ebp+dim] ; size of the vectors (it's the same)
.
.
. omitted calculations.
.
sqrtss xmm1, xmm1
movss [dist], xmm1 ; move the result to dist
fld dword [dist] ; mov in st0, that will be used by the C file
print_dist2 "distanza"
; ------------------------------------------------------------
; Function exit sequence
; ------------------------------------------------------------
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret
This is the C file:
float a[] = {6.1f, 9.5f, 12.6f};
float b[] = {25.1f, 34.1f, 9.6f};
dim = 3;
float dist = distanza(a, b, dim);
printf("d(x,y) = %f\n", dist);
This is the output:
distanza, dist: 5.46877e-315
d(x,y) = 31.227551
The C, code print the correct value, the nasm doesn't.
If I change the format string of the nasm code:
fmt2: db "%s, dist: %f",10,0
I've used %f instead of %g, the nasm output is this one:
distanza, dist: 0.000000
I have no idea what is wrong with my code, why it is not printing the correct value?
Your dist is a single 32-bit float, but printf needs a double 64-bit float. You have to transform it:
%macro print_dist2 1
section .data
.str db %1,0 ; %1 is macro call first actual parameter
section .text
sub esp, 8 ; Space for a 64-bit double floating point number
fld dword [dist] ; Load a 32-bit single floating point number
fstp qword [esp] ; Store it as 64-bit floating point number
push dword .str
push dword fmt2
call printf
add esp, 16 ; pop stack 4 * 4 bytes
%endmacro
Related
In the first loop I fill the array, then I want to print this array, but I'll have an error. It's Segmentation fault. I just change ecx register, since is my counter for _loop2.
extern printf
SECTION .bss
array resb 10
SECTION .data
fmt: db "array[%d] = %d", 10, 0 ; The printf format, "\n",'0'
SECTION .text
global main
main:
mov ecx, 0
_loop:
inc ecx
mov [array + ecx * 4], ecx
cmp ecx, 10
jnz _loop
mov ecx, 0
_loop2:
jmp print
add ecx, 1
cmp ecx, 10
jnz _loop2
ret
print:
;push ebp ; set up stack frame
;mov ebp, esp
push ecx
push dword [array + ecx * 4] ; value of variable a SECOND
push dword fmt ; address of ctrl string
call printf ; Call C function
add esp, 8 ; stack (4 * 2)
;mov esp, ebp ; takedown stack frame
;pop ebp ; same as "leave" op
mov eax,0 ; normal, no error, return value
;ret ; return
Several issues as mentioned in comments:
array resb 10 will reserve space for 10 bytes, but you want to store 10 dwords there (40 bytes). Change to array resd 10.
(Pointed out by Sep Roland) In _loop you have an off-by-one bug; since the inc is done before the mov you will access the dwords at [array+4], [array+8], ... [array+40], where the last one is out of range. This is like doing int array[10]; for (i=1; i <= 10; i++) array[i]=i; in C, and is incorrect for exactly the same reason. One fix would be to do mov [array + ecx * 4 - 4], ecx instead.
After _loop2 you have jmp print, which will transfer control to print and never come back. Since you apparently want to call print as a subroutine and continue executing with add ecx, 1 ; cmp ecx, 10, etc, you need to call print instead of jmp. And also uncomment the ret at the end of print so that it will actually return. Subroutines in assembly language don't automatically return unless you actually execute ret; otherwise the CPU will just continue executing whatever garbage happens to be next in memory.
You have a push ecx to save the value of ecx before the call to printf, which is good since printf will overwrite that register, but you need to pop ecx afterwards to get that value back and put the stack back to where it was.
Specifically, the pop ecx should follow the add esp, 8; a stack is a last-in-first-out structure, and the push ecx was before the pushing of the printf arguments, so you need to pop ecx after removing those arguments from the stack.
The mov eax, 0 as a return value at the end of print is unnecessary since you never use it anywhere else.
With these changes the code works as it should.
I'm trying to learn how to work with SSE and I decided to realize a simple code that computes n^d, using a function that gets called by a C program.
Here's my NASM code:
section .data
resmsg: db '%d^%d = %d', 0
section .bss
section .text
extern printf
; ------------------------------------------------------------
; Function called from a c program, I only use n and d parameters but I left the others
; ------------------------------------------------------------
global main
T equ 8
n equ 12
d equ 16
m equ 20
Sid equ 24
Sn equ 28
main:
; ------------------------------------------------------------
; Function enter sequence
; ------------------------------------------------------------
push ebp ; save Base Pointer
mov ebp, esp ; Move Base Point to current frame
sub esp, 8 ; reserve space for two local vars
push ebx ; save some registries (don't know if needed)
push esi
push edi
; ------------------------------------------------------------
; copy function's parameters to registries from stack
; ------------------------------------------------------------
mov eax, [ebp+T] ; T
mov ebx, [ebp+n] ; n
mov ecx, [ebp+d] ; d
mov edx, [ebp+m] ; m
mov esi, [ebp+Sid] ; Sid
mov edi, [ebp+Sn] ; Sn
mov [ebp-8], ecx ; copy ecx into one of the local vars
;
; pow is computed by doing n*n d times
;
movss xmm0, [ebp+n] ; base
movss xmm1, [ebp+n] ; another copy of the base because xmm0 will be overwritten by the result
loop: mulss xmm0, xmm1 ; scalar mult from sse
dec ecx ; counter--
cmp ecx,0 ; check if counter is 0 to end loop
jnz loop ;
;
; let's store the result in eax by moving it to the stack and then copying to the registry (we use the other local var as support)
;
movss [ebp-4], xmm0
mov eax, [ebp-4]
;
; Print using C's printf
;
push eax ; result
mov ecx, [ebp-8] ; copy the original d back since we used it as loop's counter
push ecx ; exponent
push ebx ; base
push resmsg ; string format
call printf ; printf call
add esp, 24 ; clean the stack from both our local and printf's vars
; ------------------------------------------------------------
; Function exit sequence
; ------------------------------------------------------------
pop edi ; restore the registries
pop esi
pop ebx
mov esp, ebp ; restore the Stack Pointer
pop ebp ; restore the Base Pointer
ret ; get back to C program
Now, what I'd expect is it to print
4^2 = 16
but, instead, I got
4^2 = 0
I've spent my whole afternoon on this and I couldn't find a solution, do you have any hints?
EDIT:
Since it seems a format problem, I tried converting the data using
movss [ebp-4], xmm0
fld dword [ebp-4]
mov eax, dword [ebp-4]
instead of
movss [ebp-4], xmm0
mov eax, [ebp-4]
but I got the same result.
MOVSS moves single precision floats (32-bit). I assume that n is an integer so you can't load it into a XMM register with MOVSS. Use CVTSI2SS instead. printf cannot process single precision floats, which would converted to doubles by the compiler. It's convenient to use CVTSS2SI at this point. So the code should look like:
...
;
; pow is computed by doing n*n d times
;
cvtsi2ss xmm0, [ebp+n] ; load integer
sub ecx, 1 ; first step (n^1) is done
cvtsi2ss xmm1, [ebp+n] ; load integer
loop:
mulss xmm0, xmm1 ; scalar mult from sse
sub ecx, 1
jnz loop
cvtss2si eax, xmm0 ; result as integer
;
; Print using C's printf
;
push eax ; result
mov ecx, [ebp-8] ; copy the original d back since we used it as loop's counter
push ecx ; exponent
push ebx ; base
push resmsg ; string format
call printf ; printf call
add esp, 16 ; clean the stack only from printf's vars
...
I'm new to assembly. I'm having different output for following simple code from what I expected. each time before printf is called, content of eax is shifted to the right by some number. What am I doing wrong? Thanks.
Code:
;file name : testing.asm
;assemble and link with:
;nasm -f elf testing.asm && gcc -m32 -o testing testing.o
extern printf ; the C function, to be called
SECTION .data ; Data section, initialized variables
a: dd 15 ; int a=15
str: db "content in eax=%d", 10, 0
SECTION .text ; Code section.
global main ; the standard gcc entry point
main: ; the program label for the entry point
mov ebp, esp
mov eax, [a] ; put a from store into register
shr eax, 1 ; eax content should be 15>>1 = 7
push eax
push dword str ; string to be printed
call printf ; printf(str,content_of_eax)
shr eax, 2
push eax ; eax content should be 7>>2 = 1
push dword str
call printf ; printf(str,content_of_eax)
shr eax, 1
push eax ; eax content should be 1>>1 = 0
push dword str
call printf ; printf(str,content_of_eax)
mov esp, ebp ; takedown stack frame
mov eax, 0 ; normal, no error, return value
ret ; return
Output:
content in eax=7
content in eax=4
content in eax=8
Expected Output:
content in eax=7
content in eax=1
content in eax=0
printf returns its result in eax, the original value is lost.
You should reload it from [a] or use a register that is saved across function calls such as esi, but you should save it as well and restore it before returning to the caller. You should pop the arguments passed to printf with a add esp,8 after each call to keep your stack frame consistent.
In your data section you could just use an equate for a since you only use that variable once and do not change it (i'll call it value).
fmt db "content in eax=%d",0xa,0
value equ 15
In the main function i'm pretty sure (correct me if i'm wrong) that you're supposed to save the base pointer before you update it with the stack pointer.
main:
push ebp
mov ebp, esp
Now you could create a local variable to store the current value you are working on.
sub esp, 4
From there you would just keep fetching, shifting and storing the value on the stack before each call to printf.
mov eax, value ; move 15 into eax
shr eax, 1 ; make first shift
mov dword[ebp-4], eax ; store result in local variable
push eax ; eax = 7
push fmt
call printf
add esp, 8 ; clean eax & fmt off the stack
mov eax, [ebp-4] ; fetch last shift result from variable
shr eax, 2 ; make second shift
mov dword[ebp-4], eax ; store result back in variable
push eax ; eax = 1
push fmt
call printf
add esp, 8
mov eax, [ebp-4] ; fetch last shift result from variable
shr eax, 1 ; make last shift
push eax ; eax = 0
push fmt
call printf
add esp, 8
add esp, 4 ; clean local variable
And then remember, before you return, when you release the stack frame that you also restore (pop) the base pointer.
mov esp, ebp
pop ebp
This should output:
content in eax=7
content in eax=1
content in eax=0
Remember that printf will return the number of characters transmitted to the output. So when you do this:
call printf ; printf(str,content_of_eax)
shr eax, 2
You are actually shifting the result from printf:
"content in eax=7\n" is 17 characters, so shitfting by 2 gives: 17 / 4 = 4
You need to save the value (either in a preserved register, on the stack or in memory) before shifting.
This answer seems not to be a good solution, I'm currently keeping it because of the discussion below
Like others said, printf will return it's result to eax. The result of printf is the number of bytes written.
Since you pushed the result of the shr operation to the stack, you can retrieve them again using pop, like this:
shr eax, 1 ; eax content should be 15>>1 = 7
push eax
push dword str ; string to be printed
call printf ; printf(str,content_of_eax)
pop eax
pop eax
shr eax, 2
push eax ; eax content should be 7>>2 = 1
push dword str
call printf ; printf(str,content_of_eax)
# and so on ...
I have written a program in NASM in Ubuntu11.04 which will take 2 input numbers and produce a sum. The program is the following:
section .data
msg1: db "the numbers are:%d%d",0
msg3: db "REsult= %d",10,0
section .bss
a resd 1
b resd 1
sum resd 1
section .text
global main
extern printf,scanf
main:
;; push ebp
;; mov ebp,esp
;; sub esp,10
push a
push b
push msg1
call scanf
add esp,12
mov eax,DWORD[a]
add eax,DWORD[b]
mov DWORD[sum],eax
push DWORD[sum]
push msg3
call printf
add esp,8
;; mov esp,ebp
;; pop ebp
ret
Will you pls help me to find out the mistake I have done here? I will also appreciate if you advice me any tutorial in NASM whether it is Vedio or text. I have gotten Art of Assembly Language or NASM Manual. But frst one is not based on NASM and 2nd one is difficult to get for a beginner like me.
Thanx
This should get you going:
global main
extern printf, scanf, exit
section .data
scanf_fmt db "%d %d", 0
printf1_fmt db "The numbers entered are: %d and %d,", " The result = %d", 10, 0
main:
push ebp
mov ebp, esp
sub esp, 8 ; make room for 2 dwords
lea eax, [ebp - 4] ; get pointers to our locals
lea ecx, [ebp - 8] ;
push eax ; give pointers to scanf
push ecx ;
push scanf_fmt ;
call scanf ; read in 2 dwords
add esp, 12
mov eax, dword [ebp - 4] ; add em together
add eax, dword [ebp - 8] ;
push eax ; total
push dword [ebp - 4] ; second num
push dword [ebp - 8] ; first num
push printf1_fmt ; format string
call printf ; show it
add esp, 16
add esp, 8 ; restore stack pointers
mov esp, ebp
pop ebp
call exit ; linking agaist the c libs, must use exit.
output:
I need to get my char pointer and after that i print it on the screen to see if it works ok.
I read the text from a file and put in my char pointer (sizeof(char*) + filesize) + 1.. in the end i put the '\0'.
If i printf my char* its fine
Here is my asm code
; void processdata(char* filecontent);
section .text
global processdata
extern printf
section .data
FORMAT: db '%c', 10, 0 ; to break the line 10, 0
processdata:
push ebp
mov ebp, esp
mov ebx, [ebp]
push ebx
push FORMAT
call printf
add esp, 8
when i run it i just see trash in my variable.
As violet said:
; void processdata(char* filecontent);
section .text
[GLOBAL processdata] ;global processdata
extern printf
section .data
FORMAT: db '%c', 0
EQUAL: db "is equal", 10, 0
processdata:
lea esi, [esp]
mov ebx, FORMAT
oook:
mov eax, [esi]
push eax
push ebx
call printf
inc esi
cmp esi, 0x0
jnz oook
Thanks
quote demonofnight
But if i need to increment, can i do that?
Using your original function arg of char* and your %c format, something like this:
lea esi, [esp+4]
mov ebx, FORMAT
oook:
mov eax, [esi]
push eax
push ebx
call printf
inc esi
cmp [esi], 0x0
jnz oook
[edit: ok sry, i hacked that quickly into some shenzi winOS inline __asm block]
here's a complete thing done in linux and nasm:
; ----------------------------------------------------------------------------
; blah.asm
; ----------------------------------------------------------------------------
extern printf
SECTION .data ;local variables
fmt: db "next char:%c", 10, 0 ;printf format, "\n",'0'
SECTION .text ;hack in some codes XD
global foo
foo: ;foo entry
push ebp ;set up stack frame
mov ebp,esp
mov esi, [ebp+8] ;load the input char array to the source index
oook: ;loop while we have some chars
push dword [esi] ;push next char addy in string to stack
push dword fmt ;push stored format string to stack
call printf
add esp, 8 ;restore stack pointer
inc esi ;iterate to next char
cmp byte [esi], 0 ;test for null terminator byte
jnz oook
mov esp, ebp ;restore stack frame
pop ebp
mov eax,0 ;return 0
ret ;done
blah.c (that invokes the .asm foo) :
/*-----------------------------------------------
blah.c
invokes some asm foo
------------------------------------------------*/
#include <stdio.h>
void foo(char*);
int main() {
char sz[]={"oook\n"};
foo(sz);
return 0;
}
&here's the commandline stuff:
$ nasm -f elf blah.asm -o blah.o
$ gcc -o blah blah.c blah.o
$ ./blah
next char:o
next char:o
next char:o
next char:k
next char:
$
$ nasm -v
NASM version 2.09.08 compiled on Apr 30 2011
$ uname -a
Linux violet-313 3.0.0-17-generic #30-Ubuntu SMP Thu Mar 8 17:34:21 UTC 2012 i686 i686 i386 GNU/Linux
Hope it works for you ;)
On linux x86 the first function parameter is in ecx. The printf format for printing a pointer is "%p".
So something along
...
FORMAT: db '%p', 10, 0 ; to break the line 10, 0
processdata:
mov eax, [esp+4]
push eax
push format
call printf
add esp, 8
ret
should work, assuming the rest of your code is correct and your are using gcc's calling convention.
This is assuming that the pointer you want to print is on the stack.
The reason for the crash is probably that you push 12 bytes on the stack, but correct the stack pointer by only 8.