nasm x86 beginner using C calls - printf scanf - linux

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.

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 Linux 32-bit: scanf, printf calls

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.

Beginner issues with NASM: converting from string to number, and output to the console

I am just starting to learn NASM, and I am doing a first program involving a matrix in a text file. The file contains an N*N matrix, where the first line contains N, and the other lines each contain one row of the matrix. To start along my way in completing my larger task, i borrowed some code that reads a file line by line and outputs each line to the console.
I intend to read in the first line, convert it from string to integer, move that to a register i will use as a counter, then print out that many lines of the array. I figure even if N=7 and i fiddle with the top line of the file to say 3, if i get 3 lines printed then it works! However, this didn't work. I got it to print out always one line, suggesting that the number i read in and converted to int wasn't converted properly. I tried to output this number after conversion, but attempting to do so causes a seg fault, to my suprise!
Here is my code for NASM under Linux:
; this program demonstrates how to open files for reading
; It reads a text file line by line and displays it on the screen
extern fopen
extern fgets
extern fclose
extern printf
extern exit
global main
segment .data
readmode: db "r",0
filename: db "hw6_1.dat",0 ; filename to open
error1: db "Cannot open file",10,0
format_1: db "%d",0
segment .bss
buflen: equ 256 ; buffer length
buffer: resd buflen ; input buffer
segment .text
main: pusha
; OPENING FILE FOR READING
push readmode ; 1- push pointer to openmode
push filename ; 2- push pointer to filename
call fopen ; fopen retuns a filehandle in eax
add esp, 8 ; or 0 if it cannot open the file
cmp eax, 0
jnz .L1
push error1 ; report an error and exit
call printf
add esp, 4
jmp .L4
; READING FROM FILE
.L1: mov ebx, eax ; save filepointer of opened file in ebx
; Get first line and pass to ecx
push ebx
push dword buflen
push buffer
call fgets
add esp, 12
cmp eax, 0
je .L3
;convert string -> numeric
push buffer
call parseInt
mov ecx, eax
.L2:
;debug
push ecx
push format_1
call printf
add esp, 8
push ebx ; 1- push filehandle for fgets
push dword buflen ; 2- push max number of read chars
push buffer ; 3- push pointer to text buffer
call fgets ; get a line of text
add esp, 12 ; clean up the stack
cmp eax, 0 ; eax=0 in case of error or EOF
je .L3
push buffer ; output the read string
call printf
add esp, 4 ; clean up the stack
dec ecx
cmp ecx, 0
jg .L2
;CLOSING FILE
.L3: push ebx ; push filehandle
call fclose ; close file
add esp, 4 ; clean up stack
.L4: popa
call exit
parseInt:
push ebp
mov ebp, esp
push ebx
push esi
mov esi, [ebp+8] ; esi points to the string
xor eax, eax ; clear the accumulator
.I1 cmp byte [esi], 0 ; end of string?
je .I2
mov ebx, 10
mul ebx ; eax *= 10
xor ebx, ebx
mov bl, [esi] ; bl = character
sub bl, 48 ; ASCII conversion
add eax, ebx
inc esi
jmp .I1
.I2: pop esi
pop ebx
pop ebp
ret 4
A sample data file is shown below, this is the one i was using:
4
2 45 16 22
17 21 67 29
45 67 97 35
68 34 90 72
I really dont understand how this is not working. The code to convert to integer was borrowed from WORKING programs, as is the code for output that i used to debug.
First, why are you calling printf with only one parameter? The proto for printf is:
int printf ( const char * format, ... );
Second, your program works almost fine, you are just not exiting the program correctly!! You are linking to the c library and it adds startup code, you need to call exit instead of ret. Actually, just a ret is not the correct way to exit any program in Linux or Windows.
Your exit code should be:
.L4:
popa
call exit
and add extern exit to your list of externs.
Your parseint seems to return an incorrect number
* EDIT *
Since you are still having problems with parseint, from the fgets docs at the c++ site, you are not reading the whole thing:
A newline character makes fgets stop reading, but it is considered a
valid character by the function and included in the string copied to
str.
So, what is happening is you are telling fgets to read in dword buflen number of bytes, which it will or it will stop reading when a newline is found and adds that to the buffer.
This:
; Get first line and pass to ecx
push ebx
push dword buflen
push buffer
call fgets
add esp, 12
should be:
; Get first line and pass to ecx
push ebx
push 1 ; <----- you only want to read 1 byte!
push buffer
call fgets
add esp, 12

Incorrect ESP and EIP after showing some text in Assembly

Me again, with the same kind of problems. So, this time I have created a small function that will display some text on the console. You push 2 arguments on the stack, call the function, see the text and return. This is the code:
start:
push dword MyText ; Pointer to the variable from the .data section
push dword 26 ; Number of characters to write
call ShowText
ret
ShowText:
push ebp
mov ebp, esp
push 0
push WrittenChars ; Pointer to the variable from the .bss section
push dword [ebp + 8] ; Number of characters to write
push dword [ebp + 12] ; MyText
push dword [StdHandle] ; Value of StdHandle, from the .bss section
call WriteConsoleA
pop ebp
ret
[section .data]
MyText db 'Abcdefghijklmnopqrstuvxzw', 0Ah
So, the correct values are pushed and retrieved by WriteConsoleA, the text is displayed correctly but I still get an Access Violation Error, so it looks like ESP is wrong after showing the message. I thought WriteConsoleA would clear the stack of its arguments, I don't know what happens.
ShowText has no pascal calling convetion, so in this case you must adjust the stack yourself.
call ShowText
add esp, 08

Resources