NASM Linux 32-bit: scanf, printf calls - linux

I've written simple assembly code, which uses printf and scanf to write and read numbers, to and from command line respectively.For this particular code, I'm getting output different from given input. It seems that first value printed is [var1]+[var2]*2^8 . However, by increasing size of variables var1 & var2 to 4 bytes, code gives correct output. How?
;assemble and compile with :
;nasm -f elf testing.asm && gcc -m32 -o testing testing.o
extern printf,scanf
;store eax,ebc,ecx,edx onto the stack
%macro push_reg 0
push edx
push ecx
push ebx
push eax
%endmacro
;restore eax,ebx,ecx,edx
%macro pop_reg 0
pop eax
pop ebx
pop ecx
pop edx
%endmacro
section .text
global main
main:
;reads number var1
push_reg
push var1
push formatin
call scanf ;scanf("%d",var1);
add esp,8 ;restoring stack pointer
pop_reg
;reads number var1
push_reg
push var2
push formatin
call scanf ;scanf("%d",var2);
add esp,8 ;restoring stack pointer
pop_reg
;printing number var1
push_reg
push dword[var1]
push formatout
call printf ;printf("%d",content of var1);
add esp,8 ;restoring stack pointer
pop_reg
;printing number var2
push_reg
push dword[var2]
push formatout
call printf ;printf("%d",content of var2);
add esp,8 ;restoring stack pointer
pop_reg
exit:
mov eax,1
int 0x80
section .bss
var1 resb 1
var2 resb 1
section .data
formatout: db "%d",10,0
formatin: db "%d",0
Input:
1
1
Output:
257
1

You told scanf & printf you were scanning/printing integers, which are typically 32-bit (or 4-byte) values. So they behaved as if they were, using that much data at the addresses you provided.

Related

Why can't I push variable content on stack successfully?

section .data
msg db 'enter number ',10,0
output db '%hd',0
section .bss
val resw 1
section .text
global main
extern printf
extern scanf
main :
push msg
call printf
add esp,4
push val
push output
call scanf
add esp,8
;movzx eax,word[val]
;push eax
push word[val]
push output
call printf
add esp,8
ret
push word[val]
This only pushes a word and you need to have a dword on the stack.
You can do it like:
xor ax,ax
push ax ;Gives a high word of zero, much like your MOVZX did.
push word[val]
Your segmentation fault comes from the fact that you pushed a total of 6 bytes but removed a total of 8 bytes through add esp,8.

Need some advice with NASM loop

I`m trying to make a while loop that prints from 0 through 10 but have some errors...
Compile with these:
nasm -f elf myprog.asm
gcc -m32 -o myprog myprog.o
Errors:
at output you can see 134513690.. lots of....
and at the last line a segmentation fault
This is the code:
SECTION .text
global main
extern printf
main:
xor eax,eax ; eax = 0
myloop:
cmp eax,10 ; eax = 10?
je finish ; If true finish
push eax ; Save eax value
push number ; push number value on stack
call printf
pop eax
inc eax ; eax + 1
add esp,80 ; Im not sure what is this
jmp myloop ; jump to myloop
number db "%d",10,0 ; This is how i print the numbers
finish:
mov eax,1
mov ebx,0
int 0x80
There's one real error in this code; the function call cleanup isn't quite right. I would change the myloop section to be like this:
myloop:
cmp eax,10 ; eax = 10?
je finish ; If true finish
push eax ; Save eax value
push number ; push number value on stack
call printf
add esp, 4 ; move past the `push number` line
pop eax
inc eax ; eax + 1
jmp myloop ; jump to myloop
The biggest difference is that instead of adding 80 to esp (and I'm not sure why you were doing that), you're only adding the size of the argument pushed. Also, previously the wrong value was getting popped as eax, but switching the order of the add and the pop fixes this.
A few problems, you need to push the "number" not as address, but as numeral.
push dword number
After you call printf, you need to restore the stack, ESP.
Basically when you "push" a register, it gets stored in the stack. Since you push twice (two arguments), you need to restore 8 bytes.
When you "pop eax", you're retrieving the top of the stack, which is "number", not the counter. Therefore, you just need to do
pop eax
pop eax
then there is no need to restore the ESP by adding since it is done by popping.
Basically, after the first iteration, eax points at an address, so it will never be equal to 10.
Further reading about Stack Pointer and Base Pointer:
Ebp, esp and stack frame in assembly with nasm

nasm x86 beginner using C calls - printf scanf

This code gets a name and one number from the user and adds a number (5150) to it. I can't figure out why I'm getting a segmentation fault. I get the fault after the prompt to enter the number. Here's the code:
SECTION .data
askName: db "Enter your name: ",0
askNum: db "Enter an unsigned number no more than four digits: ",0
fResultP1: db "Thank you ",0
fResultP2: db ".",0
fResultP3: db "After adding 5150 to your number, the answer is now: ", 0
formats: db "%s", 0
formatd: db "%d", 0
formatdlf: db "%d",10, 0 ; with line feed
SECTION .bss
name: resb 20
number: resb 4
;answer: resb 5
SECTION .text
extern printf
extern scanf
global main
main:
;;;;;;; set up stack frame
push EBP ; base pointer
mov EBP, ESP ; put stack pntr in EBP
pushad ; pushes all registers on stack
;;;;;;; ask user name
push askName ; push question
call printf ; print question
add ESP, 4 ; clean the stack (pop stack)
;;;;;;; get name input
push name
push formats ; %s (string)
call scanf
add ESP, 8 ; clean the stack (pop stack)
;;;;;;; ask user number
push askNum ; push question
call printf
add ESP, 4 ; pop stack
;;;;;;; get number input
push number
push formatd ; %d (decimal)
call scanf
add ESP, 8 ; pop stack 2X4= 8
;;;;;;; print closing sent
push fResultP1 ; "Thank you "
call printf
add ESP, 4 ; pop stack
push dword [name]
call printf
add ESP, 4 ; pop
push fResultP2 ; "."
call printf
add ESP, 4
push fResultP3 ; "After adding..."
call printf
add ESP, 4 ; pop
mov EAX, dword [number]
add EAX, 5150
push EAX ; push on the added number
push formatdlf ; has line feed
call printf
add ESP, 8 ; pop
;;;;;;; destroy stack frame ;;;;;;;;;;;;;;;;;
popad
mov ESP, EBP
pop EBP
ret
Change push dword [name] to push dword name (or push name). Square bracket is not need. name is the address of the name string.

Popping and printing argc from the stack

According to this paper and a few stackoverflow posts, argc is at the top of the stack and argv is below it.
I've tried about 3-4 different ways of doing it:
Popping it into an initialized variable (.data) - output done by calling printf.
Popping it into uninitialized space (.bss) - output done by calling sys_write()
A mixture of the above + tweaks.
I've been told that argc and argv aren't in the stack by someone on a forum, which I don't understand; how are other people doing it with similar code?
Here's an example of what I've attempted (3 days worth of knowledge - try not to giggle):
section .bss
argc: resd 1 ; alloc 4 bytes for popped value
section .text
global _start
_start:
pop dword[argc] ; pop argc, place in var
mov ebx,0x01 ; file descriptor = STDOUT
mov ecx,argc ; var (addr) - points to buffer
mov edx,1 ; length of buffer (single digit)
mov eax,0x04 ; syscall number for sys_write()
int 0x80 ; request the kernel to make syscall
exit:
mov ebx,0x00 ; arg for sys_exit() - sys_exit(0)
mov eax,0x01 ; syscall number for sys_exit()
int 0x80 ; request the kernel to make syscall
Solution:
section .data
msg db Value: %d\n
section .text
global main
extern printf
main:
push dword[esp+4]
push msg
call printf
add esp,8
mov eax,0
ret
The process of getting argc looks ok to me (for a 32-bit Linux machine), although you're 4 bytes off since the top of the stack most likely contains the return address to the startup code that called main.
Also, the sys_write system call expects a pointer to a string in ecx. What you're giving it is a pointer to an integer, which isn't the same thing.If you want to print the value of argc you'll have to convert it to a string first (or use the printf function).
Here's some example code (I'm using the GNU assembler since I don't have NASM on this machine):
format: .asciz "%d\n"
.text
.globl main
.type main, #function
main:
pushl 4(%esp) # push argc
pushl $format # push the format string
call printf
addl $8,%esp # pop the arguments
movl $0, %eax # return value
ret

how does this assembly proc not crash?

I have this linux nasm code here that doesn't crash. With the ret 80 instruction at the end of printString shouldn't this program crash?
bits 32
section .data
hello: db 'Hello Linux assembly!!!!!!!!!!!!!!!!!!!',10,0
helloLen: equ $-hello
anotherString db "hello im another string!!!!",10,0
anotherStringlen equ $-anotherString
section .text
global _start
_start:
push hello
push helloLen
call printString
;;;; should i pop the two paramters I pushed?
;;;; does the ret instruction do it for me?
push anotherString
push anotherStringlen
call printString
call exit
printString:
push ebp
mov ebp, esp
mov eax, 4
mov ebx, 1
mov ecx, [ebp+12]
mov edx, [ebp+8]
int 80h
pop ebp
ret 60 ;;;;; How does this not make printString crash?
exit:
mov eax,1
mov ebx,0
int 80h
Doing things incorrectly in assembly language by no means assures that you'll get a crash.
The ret 60 instruction pops the wrong number of values off the stack after returning. However, the next things you do don't assume that there are any values of use on the stack. For instance, the exit function won't care that the stack is trashed, and will still exit your process.

Resources