I am trying to make a simple program in assembler, but I do not understand why, I get a fault.
I' ve a 64 bit machine running Ubuntu 12.04, and "as" as a assembly compiler.
My goal merely is to print the string "Hello" on screen.
I wrote this:
#print.s
.section .data
.globl StringToPrint
StringToPrint: .asciz "Hello"
.globl _start
_start:
movq $4, %rax
movq $1, %rbx
movq $StringToPrint, %rcx
movq $5, %rdx
int $0x80
_done:
ret
But that's what I get:
$ as print.s -o print.o
$ ld print.o -o print
$ ./print
Hello[1] 10679 segmentation fault (core dumped) ./print
Why do you think this happens? Any idea?
Here is the fix :
#print.s
.section .data
.globl StringToPrint
StringToPrint: .asciz "Hello"
.globl _start
_start:
movl $5, %edx # string length
movl $StringToPrint, %ecx # pointer to string to write
movl $1, %ebx # file handle (stdout)
movl $4, %eax # system call number (sys_write)
int $0x80 # Passes control to interrupt vector
#sys_exit (return_code)
movl $1, %eax #System call number 1: exit()
movl $0, %ebx #Exits with exit status 0
int $0x80 #Passes control to interrupt vector
As Michael has already said you need to call sys_exit to avoid segmentation fault .
Edit :
Here is good to mention that int 0x80 invokes 32-bit system calls .
Using int 0x80 for syscall on x64 systems is used for backward compatibility to allow 32-bit applications to run .
On 64-bit systems will be correct to use syscall instruction .
Here is a working version :
.section .data
StringToPrint: .asciz "Hello"
.section .text
.globl _start
_start:
movq $1, %rax # sys_write
movq $1, %rdi # stdout
movq $StringToPrint, %rsi # pointer to string to write
movq $5, %rdx # string length
syscall
movq $60, %rax # sys_exit
movq $0, %rdi # exit code
syscall
The calling conventions differ between 32 and 64 bit applications in Linux as well as other OSs. Additionally, for Linux the system call numbers are also different. This is how you invoke the write system call in Linux amd64:
; sys_write(stdout, message, length)
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, message ; message address
mov rdx, length ; message string length
syscall
Additionally, your application needs to call sys_exit to terminate, not return using ret. Read the calling conventions for your platform.
Related
Assembly language program to read in a (three-or-more-digit) positive integer as a string and convert the string to the actual value of the integer.
Specifically, create a subroutine to read in a number. Treat this as a string, though it will be composed of digits. Also, create a subroutine to convert a string of digits to an integer.
Do not have to test for input where someone thought i8xc was an integer.
I am doing it like this. Please help.
.section .data
String:
.asciz "1234"
Intg:
.long 0
.section .text
.global _start
_start:
movl $1, %edi
movl $String, %ecx
character_push_loop:
cmpb $0, (%ecx)
je conversion_loop
movzx (%ecx), %eax # move byte from (%ecx) to eax
pushl %eax # Push the byte on the stack
incl %ecx # move to next byte
jmp character_push_loop # loop back
conversion_loop:
popl %eax # pop off a character from the stack
subl $48, %eax # convert to integer
imul %edi, %eax # eax = eax*edi
addl %eax, Intg
imul $10, %edi
decl %ecx
cmpl $String, %ecx # check when it get's to the front %ecx == $String
je end # When done jump to end
jmp conversion_loop
end:
pushl Intg
addl $8, %esp # clean up the stack
movl $0, %eax # return zero from program
ret
Also, I am unable to get the output. I am getting a Segmentation Fault. I am not able to find out what is the error in my code.
Proper interaction with operating system is missing.
In the end: you pushed the result but the following addl $8, %esp invalidates the pushed value and the final ret incorrectly leads the instruction flow to whatever garbage was in the memory pointed by SS:ESP+4 at the program entry.
When you increase the stack pointer, you cannot rely that data below ESP will survive.
Your program does not interact with its user, if you want it to print something, use system function to write.
print_String:
mov $4,eax ; System function "sys_write".
mov $1,ebx ; Handle of the standard output (console).
mov $String,ecx ; Pointer to the text string.
mov $4,edx ; Number of bytes to print.
int 0x80 ; Invoke kernel function.
end:mov $1,eax ; System function "sys_exit".
mov (Intg),ebx ; Let your program terminate gracefully with errorlevel Intg.
int 0x80 ; Invoke kernel function.
I'm currently learning x86 assembly language at school, so I could ask a dumb question (though I found nothing useful).
I have some global variables declared in the data section in the main file, and then I have a second file where there are two functions that use these global variables.
.section .data
.globl file_desc
.globl init
.globl reset
.globl rpm
file_desc: .long
init: .int
reset: .int
rpm: .long
In the _start section, I call the sys_open syscall for getting the file descriptor and I save it in the file_desc variable.
Then I call a function in the other file:
read_init:
# read the INIT and convert it
movl $SYS_READ, %eax
movl file_desc, %ebx
leal init, %ecx
movl $1, %edx
int $0x80
cmp $0, %eax # check for EOF
jle eof
jmp get_init
eof:
movl $47, init # we make the init to -1 xD
get_init:
subb $48, init # get the real value of INIT
# skip 1 byte
movl $SYS_SEEK, %eax
movl file_desc, %ebx
movl $1, %ecx
movl $1, %edx
int $0x80
ret
The problem is that when I reach the sys_lseek syscall, file_desc has been modified! I debugged with GDB to see it and after calling the read syscall the value is not the same.
In theory it shouldn't modify it, so what the heck is doing my program?
I am trying to add two 128 bits numbers using ATT assembly syntax in linux ubuntu 64b and I am debugging it in gdb so I know that after every loop the result of adding two parts is correct but how to store all 4 results together?? I was considering adding every result to the stack but I can't add the register content to the stack, right? Am I even doing it correctly? I am a real beginner in assembler but I need it for uni :/
EXIT_SUCCESS = 0
SYSEXIT = 1
number1:
.long 0x10304008, 0x701100FF, 0x45100020, 0x08570030
number2:
.long 0xF040500C, 0x00220026, 0x321000CB, 0x04520031
.global _start
_start:
movl $4, %edx
clc
pushf
_loop:
dec %edx
movl number1(,%edx,4), %eax
movl number2(,%edx,4), %ebx
popf
adcl %ebx, %eax
cmp $0, %edx
jne _loop
popf
jnc _end
push $1
_end:
mov $SYSEXIT, %eax
mov $EXIT_SUCCESS, %ebx
int $0x80
I'm using NASM for Linux and I'd like know how, in the protected mode, you can clear the screen. I found a solution using the int10h, but on the protected mode I can only use int80h. Thanks in advance.
You can write \x1b[2J to the standard output so the terminal get cleared and fix the cursor position using \x1b[H, for example in nasm:
global _start
section .data
clr db 0x1b, "[2J", 0x1b, "[H"
clrlen equ $ - clr
section .text
_start:
mov eax, 4
mov ebx, 1
mov ecx, clr
mov edx, clrlen
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
for gnu assembler:
.globl _start
.data
clr : .ascii "\x1b[2J\x1b[H"
clrlen = . - clr
.text
_start:
movl $4, %eax
movl $1, %ebx
movl $clr, %ecx
movl $clrlen, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
I've been having problems getting even the simplest of assembly programs that I write on Linux to run on my FreeBSD machine. Here's the offending code (I'm trying to keep this as simple as possible):
#counts to sixty
.section .data
.section .text
.global _start
_start:
movl $1, %ecx #move $1 into ecx
movl $1, %eax
start_loop:
addl %ecx, %eax #add ecx to eax
cmpl $60, %eax #compare $60 and eax...
je end_loop #if eax = 60 go to end_loop
cmpl $60, %eax #
jle start_loop #jump if eax is < $60...
jmp start_loop #...to start_loop
end_loop:
movl %eax, %ebx #move the value of eax into ebx because ebx holds
#the return value
movb $1, %al #Move $1 into eax (int 1 is the value for the
#exit() syscall
int $0x80
The Linux machine returns the expected resulted which is sixty, whereas the FreeBSD machine consistently returns 164 for the return code. Does anybody know why this is? If so, can you please explain to me what is happening? Also, I should mention that they are both indeed running x86 CPUs. Thanks in advance :)
Refer to the FreeBSD Developer's handbook, and you need to do:
push %eax
mov $1, %eax
push %eax
int $0x80
because:
only the system call vector is passed via register %eax, all arguments are on the stack
the FreeBSD default syscall expects an additional word on the stack, which would be a dummy for inlined uses of int $0x80 but a return address where you do a syscall via a call kernel_entry trampoline (that then can do int $0x80; ret).
If you want to use the Linux convention (some syscall args in regs, called "Alternative Calling convention" in the manual), you have to brand the executable so that the system knows you're using Linux-style syscalls.