Printing floating point numbers in assembler - linux

I'm trying to print a floating-point value from assemler calling a printf function. It works fine with strings and integer values but fails printing floats. Here is an example of working code:
global main
extern printf
section .data
message: db "String is: %d %x %s", 10, 0
end_message: db ".. end of string", 0
section .text
main:
mov eax, 0xff
mov edi, message
movsxd rsi, eax
mov rdx, 0xff
mov rcx, end_message
xor rax, rax
call printf
ret
String is: 255 ff .. end of string
So, the parameters are passed through registers: edi contains address of a formatting string, rsi and rdx contain the same number to print in decimal and hex styles, rcx contains end of a string, rax contains 0 as we do not have a float to print.
This code works fine but something changes while trying to print float:
global main
extern printf
section .data
val: dq 123.456
msg: db "Result is: %fl",10, 0
section .text
main:
mov rdi,msg
movsd xmm0,[val]
mov eax,1
call printf
mov rax, 0
ret
This code snipped can be compiled but returns segmentation fault being executed. It seems that the problem is in wrong value of xmm0 but trying to change movsd xmm0,[val] to movsd xmm0,val gives an
error: invalid combination of opcode and operands
message.
The compiler is NASM running on openSuSe 12.3
Update. I tried to make a c program and produce a .S assembly. It gives a very weird solution:
main:
.LFB2:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movq val(%rip), %rax
movq %rax, -24(%rbp)
movsd -24(%rbp), %xmm0
movl $.LC0, %edi
movl $1, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
Is it possible to write a simple printf example?

for your assembler problem:
you need to align the stack before your main program starts.
insert
sub rsp, 8
right after main:
then add it again before ret:
add rsp, 8

Related

X86_64 Assembly code segfaults and gives stack smashing error

So, for this assignment I have to write an Assembly "function" to be called by C code. The purpose of the function is, given an integer and a memory address (the address of a char array, to be used as a string), convert the integer to a string, which starting address is the memory address that is given.
I'm on Ubuntu Linux, btw.
Here's the Assembly code (I tried to make it using the Linux x86_64 ABI calling conventions)(It is in AT&T syntax):
.global dec
.type dec, #function
.text
dec:
######################### Subroutine prologue
push %rbp # Save the base pointer
movq %rsp, %rbp # Make the stack pointer the new base pointer
push %rdi # Stack parameter 1
push %rsi # Stack parameter 2
push %rbx # Save callee-saved registers
push %r12
push %r13
push %r14
push %r15
######################### Subroutine body
movq %rdi, %rax
xor %rcx, %rcx
addDigit:
cmp $0, %rax
je putMem
xor %rdx, %rdx
mov $10, %ebx
div %ebx
addq $'0', %rdx
pushq %rdx
inc %rcx
jmp addDigit
putMem:
cmp $0, %rcx
je endProg
popq (%rsi)
add $1, %rsi
dec %rcx
jmp putMem
endProg:
movq $0x0, (%rsi)
movq -16(%rbp), %rsi
mov $1, %rax
######################### Subroutine epilogue
popq %r15 # Restore callee-saved registers
popq %r14
popq %r13
popq %r12
popq %rbx
movq %rbp, %rsp # Reset stack to base pointer.
popq %rbp # Restore the old base pointer
ret # Return to caller
And here is my C code:
extern int dec(int num, char* c);
#include <stdio.h>
int main(){
char* a = "Test\n";
dec(0x100, a);
printf("Num: %s\n", a);
}
It compiles without any problems, but when I try to run, it segfaults.
I've tried debugging it with gdb, and apparently the problem occurs when I try to run the instruction
pop (%rsi)
So, I made a few changes in my C code:
extern int dec(int num, char* c);
#include <stdio.h>
int main(){
char c;
dec(0x100, &c);
printf("Num: %s\n", &c);
}
Now, when I attempt to run it, I get this message:
Num: 256
*** stack smashing detected ***: ./teste.out terminated
Aborted (core dumped)
Can someone help me understand what's going on here and how do I fix my code?
Thanks in advance.

How to read and display a value in Linux assembly?

I'm a beginner in Linux assembler and I have some questions. I'd like to read some characters from keyboard, convert it to value (I understand that this convertion should be from ASCII to decimal, right?), do some math (add, sub, multiply, whatever) and display the result in Terminal. How should I do that? I wrote some code but it probably doesn't make sense:
SYSEXIT = 1
EXIT_SUCC = 0
SYSWRITE = 4
SYSCALL = 0x80
SYSREAD = 3
.data
value: .space 5, 0
value_len: .long .-value
result: .long
result_len: .long .-result
.text
.global _start
_start:
movl $SYSREAD, %eax
movl $EXIT_SUCC, %ebx
movl $value, %ecx
movl value_len, %edx
int $SYSCALL
movl $0, %edx
movl value_len, %ecx
for:
movb value(, %edx, 1), %al
subb $48, %al
movb %al, result(, %edx, 1)
inc %edx
loop for
add $10, result
movl $0, %edx
movl result_len, %ecx
for1:
movb result(, %edx, 1), %al
add $48, %al
movb %al, result(, %edx, 1)
inc %edx
loop for1
movl $SYSWRITE, %eax
movl $SYSEXIT, %ebx
movl $result, %ecx
movl result_len, %edx
int $SYSCALL
movl $SYSEXIT, %eax
movl $EXIT_SUCC, %ebx
int $SYSCALL
I don't know if I should reserve memory by spaces? Or reading characters in loop?
How to convert it, to be able to make some math operation and then convert it to be able to display it?
I know that to get the value of ASCII char I should subtract 48, but what next?
I had an idea to multiply each bits by 2^k where k is 0,1,2...n it's good idea? If so, how to implement something like this?
As you can see I had a lot of questions, but I only need to someone show me how to do, what I am asking about. I saw some similar problems, but nothing like this in Linux.
Thank you in advance for the all information.
All the best.
At first reading and writing the console in Linux is by using the file functions with special console handles, that have always the same values: STDIN=0, STDOUT=1 and STDERR=2.
At second you will need some decent documentation about Linux system calls. Notice that the C-centric one (like "man") are not suitable, because C language does not use the system calls directly, but has wrappers that often change the arguments and the result values.
On the following site you can download an assembly-centric SDK for Linux, that contains the needed documentation and many examples and include files.
If you only need the help files, you can browse them online: Here
If the problem is the conversion from ASCII string to number and then back to string, here are two simple procedures that can do the job, if the requirements are not so big. The StrToNum is not so advanced, it simply convert decimal unsigned number:
; Arguments:
; esi - pointer to the string
; Return:
; CF=0
; eax - converted number
; edx - offset to the byte where convertion ended.
;
; CF=1 - the string contains invalid number.
;
StrToNum:
push ebx esi edi
xor ebx,ebx ; ebx will store our number
xor eax,eax
mov al,[esi]
cmp al,'0'
jb .error
cmp al,'9'
jbe .digit
jmp .error
.digit:
sub al,'0'
add ebx,eax
inc esi
mov al,[esi]
cmp al,'0'
jb .finish
cmp al,'9'
ja .finish
mov edx,ebx ; multiply ebx by 10
shl ebx,3
add ebx,edx
add ebx,edx
jmp .digit
.finish:
mov eax, ebx
mov edx, esi
clc
pop edi esi ebx
ret
.error:
stc
pop edi esi ebx
ret
NumToStr is pretty flexible. It converts number to a string in any radix and with sign:
;**********************************************************************************
; NumToStr converts the number in eax to the string in any radix approx. [2..26]
; Arguments:
; edi - pointer to the string buffer
; ecx - radix
; eax - number to convert.
; There is no parameter check, so be careful.
; returns: edi points to the end of a converted number
;**********************************************************************************
NumToStr:
test eax,eax
jns NumToStrU
neg eax
mov byte [edi],"-"
inc edi
NumToStrU:
cmp eax,ecx
jb .lessA
xor edx,edx
div ecx
push edx
call NumToStrU
pop eax
.lessA:
cmp al, 10
sbb al, 69h
das
stosb
ret

How to read input string from keyboard using assembly language

I'm trying to write a simple program that takes string from the keyboard, then prints it to the screen. So far I couldn't make it work.
Here's the code:
.section .rodata
output: .string "you entered %s\n"
input: .string "%s"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
subl $100, %esp
pushl $input
call scanf
movl %ebp, %esp
subl $100, %esp
pushl $output
call printf
xorl %eax, %eax
movl %ebp, %esp
popl %ebp
ret
When I execute it, the output is you entered (null) for any given input.
when I set the offset of subl $100, %esp command (the one before call print) to subl $104, %esp I get you entered %s, and when the offset is set to 108 I get you entered *gibberish*.
I feel like it's a game where I need to guess where scanf saved the string on the stack (why isn't it where it should be?).
I am using IA32 instruction set.
Any help would be greatly appreciated.
Basically there are 3 problems in your program:
subl $100, %esp
pushl $input
# Error 1:
# As Frank Kotler already wrote at this point
# only $input is stored on the stack; however
# the address of the buffer must also be on
# the stack (see Frank Kotler's comment)
call scanf
movl %ebp, %esp
# Error 2:
# Now the buffer is below ESP.
# Because interrupts use the kernel stack they
# will not overwrite the memory below ESP.
# However signals will destroy the memory below
# ESP!!
#
# Instead of the lines:
# movl %ebp, %esp
# subl $100, %esp
#
# You should use something like this:
# add $8, %esp
# or:
# lea -100(%ebp), %esp
#
subl $100, %esp
# Error 3:
# As for "scanf" the second argument
# is missing on the stack
pushl $output
call printf
[org 0x0100]
jmp start
;=======Data===================================
s1: db 'Enter String: $'
s2: db 'Reversed String:$'
linefeed: db 10, '$'
;=======Read string and store into stack=======
start: mov dx, s1
mov ah, 09h
int 21h
mov dx, linefeed
mov ah, 09h
int 21h
mov si,0
mov bx,0
again: mov ah, 01h
int 21h
cmp al,byte 0dh
je endread
Page 8 of 10
mov bl,al
push bx
inc si
cmp si,15
je endread
jmp again
endread: Push si
;=======Read from stack and print to screen=====
mov dx, linefeed
mov ah, 09h
int 21h
mov dx, s2
mov ah, 09h
int 21h
mov dx, linefeed
mov ah, 09h
int 21h
pop si
r1: pop bx
mov dl,bl
mov ah, 02h
int 21h
dec si
cmp si,0
jne r1
mov dx, linefeed
mov ah, 09h
int 21h
mov ax, 0x4c00 ;terminate program
int 21h

linux x64 addition program

I am making an addition program using x64 assembly, but it does not display a value when run (compiled with nasm, elf64).
section .text
global _start
_start:
mov rax, 0
add rax, [num1B]
add rax, [num2B]
mov [result], rax
mov rsi, [result]
;mov rdx, 8
mov rax, 4
mov rdi, 1
int 80h
mov rax, 1
mov rdi, 0
int 080h
section .data
num1B: dq 0Ah
num2B: dq 0Ah
result: dq 00h
Does anyone know why this is not displaying anything
1.later use printf instead of interrupts, much better,
2.why put values of numB1 and numB2 instead of their location.
Use: mov rax, numB1.
3.in 64bit nasm assembly you use the:
rdi, rsi, rbx, rcx,... Registers for putting in values for interrupts.
For example:
mov rdi, 01
mov rsi, 00
syscall
DON't USE int0x80!, for more-portability use syscall and besides int 0x80 didn't work on my system.
Hope it helps, Correct me if I'm wrong.
Looks like you want to print 'result' to stdout and you are using the 32-bit
system call values.
In 64-bit linux the system call for write is 1 and you would write to stdout like this... att&t syntax:
first strip values in %rax and push them byte by byte on stack, say %rax
holds the value 0x7ffffff8:
mov $0xa, %rbx # divisor
nibble:
xor %rdx, %rdx # will hold bytes values you need
div %rbx, %rax
push %rdx # save remainder
inc %r8 # count digit, write seems to trash %rcx
cmp $0, %rax # done?
jne nibble # no, get another digit
#set up for write to stdout
mov $1, %rax # sys_call for write
mov $1, %rdi # write to stdout
mov $result, %rsi # addr. of value to print
# now get values from stack, make ascii and write to stdout
decimal:
pop %rdx # get digit off stack
add $0x30, %dl # make ascii printable
movb %dl, result # load addr. with value
mov $1, %rdx # print 1 byte
syscall
dec %r8
jnz decimal # go till %r8 is zero
You just need to set up a 1 byte data holder for digits,either in data section:
.section .data
result:
.byte 0 # reserves 1 byte and inits to 0
or the uninitialized data area:
.section .bss
.lcomm result, 1 # reserves 1 byte
I'm sure there are better ways to do this, should give you some ideas though.
Get a 64-bit system call list, they have changed quite a lot from the 32-bit calls.

Read Multiple bytes from stack into single register

I am using 64-bit linux and programming in assembler using gas. The issue I am having is I let the user enter lets say "1 + 12" using the system call read, and saving it as follows.
My read function:
.type _read, #function
_read:
pushq %rbp # Save old base pointer
movq %rsp,%rbp
movq $200,%rdx # MAX characters to retrieve
movq $equation,%rsi # Buffer for equation string
movq $0,%rdi # STDIN
movq $0,%rax # SYS_READ
syscall
movq %rbp,%rsp # Restore base pointer
popq %rbp
ret # Return from function
equation is declared as:
.section .bss
.lcomm equation, 200
So I parse through each byte of equation trying to save the numbers, but if they enter "12" than I would first get 1 and than 2, I need to somehow save 12 on the stack and be able to just popq %rax and have "12" in there. I am not sure how to go about this? Any input would be greatly appreciated.
You'll have to write some sort of parser. Here's an example (I'm using 16-bit assembly in Intel syntax, but you get the gist of it):
; Parses the zero-terminated string 'equation', converts any numbers
; found in that string from strings to integers and pushes them on
; the stack.
parse_equation:
pop di ; pop the return address
lea si,[equation]
cld
xor cl,cl ; # of chars in the currently parsed number
skip_non_number:
lodsb
test al,al
jz end_of_equation
cmp al,'0'
jb skip_non_number
cmp al,'9'
ja skip_non_number
sub al,'0' ; convert '0'..'9' -> 0..9
movzx bx,al ; zero-extend to word and store in bx
parse_number:
inc cl
lodsb
test al,al
jz end_of_equation
cmp al,'0'
jb end_of_number
cmp al,'9'
ja end_of_number
sub al,'0'
mov ch,al
mov ax,10
mul bx
movzx bx,ch
add bx,ax ; bx = bx*10 + (word)al
jmp parse_number
end_of_number:
push bx ; store the parsed number on the stack
xor cl,cl
jmp skip_non_number ; start over again
end_of_equation:
test cl,cl
jz nothing_to_push
push bx ; the string ended with a number; push it
nothing_to_push:
jmp di ; return
My code ignores anything that isn't a number (like arithmetic operators), and doesn't handle signed numbers. I'll leave it to you to figure out how to handle such things.

Resources