NASM Code In Linux Gives Me Segmentation Fault - linux

I started learning how to write programs using the NASM assembly programming language. I wrote this simple program that prompts the user to enter two numbers and then adds the two operands together. I got it to compile with no errors or warnings, but when it prompts the user for the two numbers and it begins to add the two numbers it prints out segmentation fault and program ends. I know a segmentation fault is the equivalent to an access reading / writing violation exception in the Win32 world. But, because I don't know how to debug NASM code; I can't figure out what is wrong. I suspect it has to do with an invalid pointer; but I don't know. Here is the code below:
section .data
msg1: db 'Please Enter A Number: ', 0
length1: equ $ - msg1
msg2: db 'Please Enter A Second Number: ', 0
length2: equ $ - msg2
section .bss
operand1: resb 255
operand2: resb 255
answer: resb 255
section .text
global _start
_start:
; Print first message
mov eax, 4
mov ebx, 1
mov ecx, msg1
mov edx, length1
int 80h
; Now read value
mov eax, 3
mov ebx, 1
mov ecx, operand1
mov edx, 255
int 80h
; Print second message
mov eax, 4
mov ebx, 1
mov ecx, msg2
mov edx, length2
int 80h
; Now read second value
mov eax, 3
mov ebx, 1
mov ecx, operand2
mov edx, 255
int 80h
; Now add operand1 and operand2 and print answer
mov eax, 4
mov ebx, 1
xor ecx, ecx ; Make the ecx register 0
mov ecx, operand1
add ecx, operand2
mov edx, 510
int 80h

(Aside: you should be reading from STDIN_FILENO = 0, not STDOUT_FILENO = 1. Also, you're writing a NUL character and you shouldn't.)
The problem is that operand1 and operand2 are addresses to memory locations holding characters you've read. When you add them, you get a pointer to invalid memory.
You'll have to convert them to integers, add them, and convert back to a string, before you can write it out.

Value in ecx is an address of string that is to be printed when you call int 80h. Last part does not make sense
mov eax, 4
mov ebx, 1
xor ecx, ecx ; Make the ecx register 0
mov ecx, operand1
add ecx, operand2 ; **<<< invalid memory address now in ECX !!!**
mov edx, 510
int 80h
because you are adding address of string operand1 and address of string operand2 and trying to print whatever is located ant resulting address which is most likely points to nowhere.
To debug your program with gdb you can do:
nasm -f elf64 -g -l q1.lst q1.asm
gcc -o q1 q1.o
I replaced the "_start" with "main" so that gcc won't complain, and you can skip the 64 in "-f elf64" if you are building on 32 bit platform.
gdb q1
Here is an example f gdb session:
(gdb) br main
Breakpoint 1 at 0x4004d0: file q1.asm, line 20.
(gdb) r
Starting program: /home/anonymous/Projects/asm/q1
Breakpoint 1, main () at q1.asm:20
20 mov eax, 4
(gdb) n
21 mov ebx, 1
(gdb) n
22 mov ecx, msg1
(gdb) n
23 mov edx, length1
(gdb) p msg1
$1 = 1634036816
(gdb)

Related

Segmentation Fault while replacing a character x86 NASM on Linux

I'm getting a segmentation fault after writing mov [gtt+4], byte '>' where my variable is defined as gtt: db "I'm ! than 10".
I feel like it might be an error when assembling the program.
I'm using the commands: nasm -f elf file.asm -o file.o, ld -m elf_i386 file.o -o file
I have tried to use elf32 rather than elf but it doesn't make a difference.
The purpose of my program is to loop 2 times, multiplying whatever is in ebx by 2 each time. Afterwards, it will compare if ecx > 10 and displaying the corresponding string. I'm trying to get it to replace the "!" with either "<" or ">".
I'm using Ubuntu, and I'm working in x86 assembly.
Here is my full code snippet:
section .data:
starti: db "Starting value: 1", 0x0a
startil equ $-starti
gtt: db "I'm > than 10!", 0x0a
gttml equ $-gtt
section .text:
_start:
mov eax, 4
mov ebx, 1
mov ecx, starti
mov edx, startil
int 0x80
mov ebx, 1 ; Start value!
mov ecx, 2 ; Number of iterations
label:
add ebx, ebx ; Add 2*ebx
dec ecx ; ecx -= 1
cmp ecx, 0 ; If ecx > 0, loop again
jg label
cmp ebx, 10 ; If cbx > 10, jump to gtt-g
jg gttg
mov [gtt+4], byte '<'
mov eax, 4 ; If cbx < 10, output <
mov ebx, 1
mov ecx, gtt
mov edx, gttml
int 0x80
mov eax, 1 ; Exit gracefully
mov ebx, 0
int 0x80
gttg:
mov [gtt+4], byte '>'
mov eax, 4 ; Display gtt
mov ebx, 1
mov ecx, gtt
mov edx, gttml
int 0x80
mov eax, 1 ; Exit gracefully
mov ebx, 0
int 0x80
Fix
Thanks to Jester for this, "you must not use colons after section names, they are not labels. As it is, the colon is included in the name and hence the assembler doesn't recognize them as standard sections and doesn't apply the expected attributes meaning your data is read only. TL;DR: use section .data and section .text without a trailing".

Converting user input to all caps in assembly (NASM) [duplicate]

This question already has answers here:
X86 NASM Assembly converting lower to upper and upper to lowercase characters
(5 answers)
X86 Assembly Converting lower-case to uppercase
(1 answer)
Closed 3 years ago.
I want to change the string to all caps, although I am having trouble getting the length of the input. What i have tried so far is moving the address of the message into a registrar then indexing through the string and also increment a counter variable. Then comparing the char in the address to a '.' (signifying the end of the message) and if its found not to be equal it will recall this block of statements. At least this is what I want my code to do. Not sure if this is even the right logic. I know there are alot of errors and its messy but I'm learning so please just focus on my main question. thank you! EDIT: the input i use is 'this is a TEST.'
;nasm 2.11.08
SYS_Write equ 4
SYS_Read equ 3
STDIN equ 0
STDOUT equ 1
section .bss
message resb 15
counter resb 2
section .data
msg1: db 'Enter input (with a period) that I will turn into all capitals!',0xa ;msg for input
len1 equ $- msg1
section .text
global _start
_start:
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, msg1 ; msg to print
mov edx, len1 ; len of message
int 0x80 ; Call the kernel
mov eax, SYS_Read ;system call to read input
mov ebx, STDIN ;file descriptor
mov ecx, message ;variable for input
mov edx, 15 ;size of message
int 0x80 ;kernel call
mov [counter], byte '0'
getLen:
mov eax, message
add eax, [counter]
inc byte [counter]
cmp eax, '.'
jne getLen
mov eax, SYS_Write ; this is to print the counter to make sure it got the right len
mov ebx, STDOUT
mov ecx, counter
mov edx, 2
int 0x80
jmp end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov eax, [message]
;add eax, counter
cmp eax, 90
jg toUpper
toUpper:
sub eax, 32
mov [message], eax
mov eax, SYS_Write ; The system call for write (sys_write)
mov ebx, STDOUT ; File descriptor 1 - standard output
mov ecx, message ; Put the offset of hello in ecx
mov edx, 10 ; helloLen is a constant, so we don't need to say
int 0x80 ; Call the kernel
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
end:
mov eax,1 ; The system call for exit (sys_exit)
mov ebx,0 ; Exit with return code of 0 (no error)
int 0x80 ;

Behavior of read syscall in Assembly (ASM)

I am currently learning the ASM, I have a question about the following code (which compiles)
This code come from this tutorial.
The question is: Why do I have the same behaviour when the fd is egual to 0, 1 or 2 (corresponding to stdin, stdout and stderr), at the indicated line, and when the fd is egual to 3 or more, it does nothing (it skips the scanf).
section .data ;Data segment
userMsg db 'Please enter a number: ' ;Ask the user to enter a number
lenUserMsg equ $-userMsg ;The length of the message
dispMsg db 'You have entered: '
lenDispMsg equ $-dispMsg
section .bss ;Uninitialized data
num resb 5
section .text ;Code Segment
global _start
_start: ;User prompt
mov eax, 4
mov ebx, 1
mov ecx, userMsg
mov edx, lenUserMsg
int 80h
;Read and store the user input
mov eax, 3
mov ebx, 2 ; /!\ QUESTION IS ABOUT THIS LINE /!\
mov ecx, num
mov edx, 5 ;5 bytes (numeric, 1 for sign) of that information
int 80h
;Output the message 'The entered number is: '
mov eax, 4
mov ebx, 1
mov ecx, dispMsg
mov edx, lenDispMsg
int 80h
;Output the number entered
mov eax, 4
mov ebx, 1
mov ecx, num
mov edx, 5
int 80h
; Exit code
mov eax, 1
mov ebx, 0
int 80h
We can compile and execute this code with the following command:
$> nasm -f elf64 test.S
$> ld test.o
$> ./a.out
Thank you,

Writing integer to console gives Segmentation Fault

Going from high to low lever language I got to assembly. Now at the very beginning, I wrote a simple age program (I'm not clear how to get system time yet so I just used another input). I get Segmentation Fault (core dumped) after I enter the final input. Here is my code:
section .text
global _start
_start:
mov edx, lenask
mov ecx, ask
mov ebx, 1
mov eax, 4
int 0x80
mov edx, 5
mov ecx, input
mov ebx, 2
mov eax, 3
int 0x80
mov edx, lenask2
mov ecx, ask2
mov ebx, 1
mov eax, 4
int 0x80
mov edx, 5
mov ecx, input2
mov ebx, 2
mov eax, 3
int 0x80
mov eax, input2
mov ebx, input
sub eax, ebx
push eax
mov edx, lenanswer
mov ecx, answer
mov ebx, 1
mov eax, 4
int 0x80
pop eax
mov edx, 7
mov ecx, eax
mov ebx, 1
mov eax, 4
int 0x80
section .data
ask db "What is your age?"
lenask equ $-ask
ask2 db "What is today's year?"
lenask2 equ $-ask2
answer db "The age you were born was: "
lenanswer equ $-answer
section .bss
input resb 5
input2 resb 5
An example of what happens:
What is your age?45
What is today's year?2015
The age you were born was: Segmentation fault
It should have done:
What is your age?45
What is today's year?2015
The age you were born was: 1970
The problem is that int 0x80 with eax set to 4 calls the kernel's sys_write function (i.e. a write system call) which expects a pointer to a string. By providing a integer to the function call the kernel will think that the integer is a pointer to a memory location. Because 1970 is not a valid pointer it will raise a -EFAULT. To bypass this you need to code a ToString function to convert the number to a string and then pass the pointer to the converted string.
The Segmentation Fault itself is caused by not having a sys_exit call. The reason for this is that the program will continue past the end of your code (usally into a bunch of 00 00)

x86 Intel Assembly Linux sys_write + sys_read

The following code:
section .bss
name: resb 50
section .text
global _start
_start:
PUSH EBP
MOV EBP, ESP
MOV EDX, len
MOV ECX, msg
MOV EBX, 1
MOV EAX, 4
INT 0x80
MOV EDX, 50
MOV ECX, name
MOV EBX, 0
MOV EAX, 3
INT 0x80
MOV EBX, 1
MOV EAX, 4
INT 0x80
MOV EDX, cm
MOV ECX, ex
MOV EBX, 1
MOV EAX, 4
INT 0x80
MOV EBX, 0
MOV EAX, 1
INT 0x80
section .data
msg db 'Hello!',0xa
ex db '!',0xa
len equ $ - msg
cm equ $ - ex
I intended to make a simple I/O program that printed Hello!, asked for a char and would print %c!.
Input being | and output being :, I get the following:
:Hello!
:!
|4
:4
:!
How do I make it so that it returns the following
:Hello!
|4
:4!
As Damien_The_Unbeliever says, your equs want to come immediately after the string they're supposed to measure. After your sys_read, eax will be the number of characters read, including the linefeed that ends the reading. You probably don't want to print the linefeed (in this case - sometimes you would). So:
mov edx, eax
dec edx
Or if you want to do it in one instruction:
lea edx, [eax - 1]
As it stands, edx still holds 50, so your next sys_write will print 50 characters. It will NOT stop at a zero or any other string-terminator. ecx will still contain name, but I would reload it just for clarity.
By rights, you should check for an error return (eax would be negative) after each and every int 0x80 but an error is unlikely here.

Resources