.section .data
.section .text
.globl _start
_start:
movl $1, %eax # this is the linux kernel command
# number (system call) for exiting
# a program
movl $4, %ebx # this is the status number we will
# return to the operating system.
# Change this around and it will
# return different things to
# echo $?
int $0x80 # this wakes up the kernel to run
# the exit command
But if I remove the last line of code int 0x80 , then it'll cause a segment fault.
I don't know why? Can anyone tell me.
Thanks for your time.
Thanks everyone. Now I get the answer.
Without the line of code int $0x80 , the system doesn't know that whether this application has ended or when this application ended. So it will cause crash.
If you remove the int 0x80 you will have a segmentation fault because it will begin executing whatever random bytes were in RAM immediately following your program. You really can't predict what will be there and other things can certainly happen, but a segfault is likely because the random data will very likely work out to be a memory access outside of your process memory.
Related
I just started to learn assembly by following "Programming From The Ground Up" and already hit my first issue with the first ever program. I got a segfault for the following code which is supposed to be an exit program:
.section .data
.section .text
.global _start
_start:
movl $1, %eax
movl $0, %edi
int $0x80
I've looked into it and one thing suggested was to not use int $0x80 anymore since its a legacy way to invoke system call so I tried to use syscall instead but it didn't fix it.
the commands I used are as follow:
as test.s -o test.o
ld test.o -o test
./test
I am using the Windows Subsystem for Linux.
I tried to look at it in a debugger and what I found was that after my code, there would be an endless stream of add %al, (%rax) with each memory address from 0x40100c and onwards having this line.
I have absolutely no idea what is happening and would appreciate any help.
I try to use printf from my assembler code, this is a minimal example which should just print hello to stdout:
.section .rodata
hello:
.ascii "hello\n\0"
.section .text
.globl _start
_start:
movq $hello, %rdi # first parameter
xorl %eax, %eax # 0 - number of used vector registers
call printf
#exit
movq $60, %rax
movq $0, %rdi
syscall
I build it with
gcc -nostdlib try_printf.s -o try_printf -lc
and when I run it, it seems to work: the string hello is printed out and the exit status is 0:
XXX$ ./try_printf
hello
XXX$ echo $?
0
XXX$
But when I try to capture the text, it is obvious, that something is not working properly:
XXX$ output=$(./try_printf)
XXX$ echo $output
XXX$
The variable output should have the value hello, but is empty.
What is wrong with my usage of printf?
Use call exit instead of a raw _exit syscall after using stdio functions like printf. This flushes stdio buffers (write system call) before making an exit_group system call).
(Or if your program defines a main instead of _start, returning from main is equivalent to calling exit. You can't ret from _start.) Calling fflush(NULL) should also work.
As Michael explained, it is OK to link the C-library dynamically. This is also how it is introduced in the "Programming bottom up" book (see chapter 8).
However it is important to call exit from the C-library in order to end the program and not to bypass it, which was what I wrongly did by calling exit-syscall. As hinted by Michael, exit does a lot of clean up like flushing streams.
That is what happened: As explained here, the C-library buffers the the standard streams as follows:
No buffering for standard error.
If standard out/in is a terminal, it is line-buffered.
If standard out/in is a not a terminal, it is fully-buffered and thus flush is needed before a raw exit system call.
Which case applies is decided when printf is called for the first time for a stream.
So if printf_try is called directly in the terminal, the output of the program can be seen because hello has \n at the end (which triggers the flush in the line-buffered mode) and it is a terminal, also the 2. case.
Calling printf_try via $(./printf_try) means that the stdout is no longer a terminal (actually I don't know whether is is a temp file or a memory file) and thus the 3. case is in effect - there is need for an explicit flush i.e. call to C-exit.
The C standard library often contains initialization code for the standard I/O streams — initialization code that you're bypassing by defining your own entry point. Try defining main instead of _start:
.globl main
main:
# _start code here.
and then build with gcc try_printf.s -o try_printf (i.e., without -nostdlib).
I try to use printf from my assembler code, this is a minimal example which should just print hello to stdout:
.section .rodata
hello:
.ascii "hello\n\0"
.section .text
.globl _start
_start:
movq $hello, %rdi # first parameter
xorl %eax, %eax # 0 - number of used vector registers
call printf
#exit
movq $60, %rax
movq $0, %rdi
syscall
I build it with
gcc -nostdlib try_printf.s -o try_printf -lc
and when I run it, it seems to work: the string hello is printed out and the exit status is 0:
XXX$ ./try_printf
hello
XXX$ echo $?
0
XXX$
But when I try to capture the text, it is obvious, that something is not working properly:
XXX$ output=$(./try_printf)
XXX$ echo $output
XXX$
The variable output should have the value hello, but is empty.
What is wrong with my usage of printf?
Use call exit instead of a raw _exit syscall after using stdio functions like printf. This flushes stdio buffers (write system call) before making an exit_group system call).
(Or if your program defines a main instead of _start, returning from main is equivalent to calling exit. You can't ret from _start.) Calling fflush(NULL) should also work.
As Michael explained, it is OK to link the C-library dynamically. This is also how it is introduced in the "Programming bottom up" book (see chapter 8).
However it is important to call exit from the C-library in order to end the program and not to bypass it, which was what I wrongly did by calling exit-syscall. As hinted by Michael, exit does a lot of clean up like flushing streams.
That is what happened: As explained here, the C-library buffers the the standard streams as follows:
No buffering for standard error.
If standard out/in is a terminal, it is line-buffered.
If standard out/in is a not a terminal, it is fully-buffered and thus flush is needed before a raw exit system call.
Which case applies is decided when printf is called for the first time for a stream.
So if printf_try is called directly in the terminal, the output of the program can be seen because hello has \n at the end (which triggers the flush in the line-buffered mode) and it is a terminal, also the 2. case.
Calling printf_try via $(./printf_try) means that the stdout is no longer a terminal (actually I don't know whether is is a temp file or a memory file) and thus the 3. case is in effect - there is need for an explicit flush i.e. call to C-exit.
The C standard library often contains initialization code for the standard I/O streams — initialization code that you're bypassing by defining your own entry point. Try defining main instead of _start:
.globl main
main:
# _start code here.
and then build with gcc try_printf.s -o try_printf (i.e., without -nostdlib).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I'm trying to write an assembly program for Linux assembly x86 that erases a file from a directory. Any tips?
maybe something like this:
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
.section .text
.globl _start
_start:
movl $10, %eax # unlink syscall
movl $fpath, %ebx # path to file to delete
int $0x80
movl %eax, %ebx # put syscall ret value in ebx
movl $1, %eax # exit syscall
int $0x80
then check the return value at the command line, 0 being success.
$>echo $?
I tried this code and it would not unlink a file if invoked from the same
directory as the file to delete, it would unlink files from other dirs.
This is 32 bit code so on a 64 bit os if your source file was un-link.s,
you would need to create the executable with:
$> as --32 -gdwarf2 un-link.s -o un-link.o
leave out the -gdwarf2 if you don't need to run it with gdb debugger,
then link with:
$> ld -m elf_i386 un-link.o -o un-link
hope it works for you
I see alot of people using int 0x80 for this, this is deprecated and for most things, you should not use it because it is extremely slow and is subject to possible removal at any point in future. The only cases where you should use int 0x80 would be in a case where space saving is much more important than speed or where sysenter is not supported on the target platform (pre-Pentium 4 CPUs).
In x86 Linux syscalls work by having the syscall code in eax and any arguments for it in the successive registers, ebx, ecx etc. The return value of the syscall will be placed in eax.
mov eax, 0xa ;0xa is the 'unlink' syscall, which removes a file
mov ebx, <location in memory of a null terminated string containing a path>
push <LABEL TO JUMP TO AFTER SYSENTER IS COMPLETE>
push ecx
push edx
push ebp
mov ebp, esp
sysenter
If you don't care about your registers being filled with garbage after the syscall finishes (such as in cases where you'll be overwriting the contents of those registers immediately anyway) you can use this trick to save some space and speed things up a little:
mov eax, 0xa ;0xa is the 'unlink' syscall, which removes a file
mov ebx, <location in memory of a null terminated string containing a path>
push <LABEL TO JUMP TO AFTER SYSENTER IS COMPLETE>
lea ebp, [esp-12]
sysenter
If you want to write assembly code that erases a file from a directory, you can use multiple methods, but one of the best ways is to use the linux systemcall 'unlink'. In order to have to use the proper system call, you have to figure out if you have an x86 system, or an x86-64 system, or any other kind of system. I will specify how to do this using only x86/x86-64.
So system calls work as following in linux:
1.
You put a number into return register (eax or rax depending on system) that corresponds to a system call's number, like $1 is sys_exit on x86 and $29 is sys_pause, you have to make sure you get the right number in %eax or it won't work. (I feel the need to emphasize this, this number is SYSTEM DEPENDENT, so an x86 syscall number in %eax will not do the same thing in an x86-64 system). Also, OS's may tamper with this as well, I will only talk about linux, I can't speak for any other OS.
2.
Then you move the arguments into the proper registers that is specified BY THE SYSTEM, again, find a reference for your specific system, and you will know which registers to put your arguments for the function into (some syscalls don't need arguments, so this step is unnecessary, why would you need an argument for sys_exit, idk).
3.
Then finally you use syscall for your system to let the system know to run a specific function (the one you specified by putting a number into %eax/%rax).
Let's look at an example of some assembly code that deletes a file in two different systems, x86, and x86-64 (windows has its own method, but I will not talk about that one, although it does exist). If I wanted to delete/unlink the file stored at address 0x7fff50 (let's say you don't want to specify fpath and you know the address)
In x86:
movl $10, %eax # defines which systemcall we are using (10th)
movl $0x7fff50, %ebx # moves the address of file we want to delete into %ebx (this is where the argument of sys_unlink(x86) is stored)
int $0x80 # equivalent of syscall that starts the appropriate function
In x86-64:
movq $87, %rax # defines which systemcall we are using (87th)
movq $0x7fff50, %rdi # moves the address of file we want to delete into %rdi (this is where the argument of sys_unlink(x86-64) is stored)
syscall # starts the appropriate function
If you are more of a normal person and don't know the absolute address of the file you are trying to delete, we have an easy way to write relative addresses of the file itself, like so (as copied from the other answer)
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
then the system itself will figure out where the absolute path (something like 7fff34fb) to the file is, and move that into the register when you compile the assembly. Might look like this
In x86-64:
.section .data
fpath:
.asciz "/home/user/filename" # path to file to delete
.section .text
.globl _start
_start:
movq $87, %rax # defines which systemcall we are using (87th)
movq $fpath, %rdi # moves the address of file we want to delete into %rdi
# (this is where the argument of sys_unlink(x86-64) is stored)
syscall # starts the appropriate function
You can access the output of the function (usually 0 for success or 1 for fail status) by looking at the %eax register. After each syscall, an integer is returned in %eax
You can put this text into a text file 'program.s' (I would suggest using notepad/notepad++, '.s' stands for assembly code) and compile it using gcc with $ gcc -c program.s to get the object code, and you can print and look at the object code and the hex keys involved with each command using $ objdump -d program.o
For more information about how to look up which syscall is which number and which register to put the arguements in, go here:
For x86-64: https://filippo.io/linux-syscall-table/
So I'm confused. I'm going through the book "Programming from the Ground Up" and am working with using libraries.
printf is working just fine so long as I include a "\n" in the string, but without it it will print absolutely nothing.
Any idea why this happens?
Code:
.section .data
my_str:
.ascii "Jimmy Joe is %d years old!\n\0"
my_num:
.long 76
.section .text
.globl _start
_start:
pushl my_num
pushl $my_str
call printf
movl $1, %eax
movl $0, %ebx
int $0x80
Also, when I use -m elf_i386 for 32-bit mode and -dynamic-linker /lib/ld-linux.so.2 -lc to link, I get the warning
ld: skipping incompatible /usr/lib64/libc.so when searching for -lc
If that makes any difference, or if anybody has any suggestions as to how to have it load the 32-bit library directly.
Thanks!
The problem is that printf by default just prints stuff into the stdout buffer. Things won't actually be printed until the buffer is flushed. The depends on the buffering mode of stdout, but, by default, it is line-buffered, which means it gets flushed every time you print a newline character.
To flush explicitly in C, you call fflush; you can do that in asm code with
pushl stdout
call fflush
addl $4, %esp
Alternately, you can call the stdlib exit function (which flushes all I/O buffers before actually exiting), instead of using the _exit system call, which does not.
It seems you try to link your 32-bit program against the (system default) 64Bit c library.
Check if you have libs32 packages installed.
To find out which libraries a program or other dynamically loads froum the LD_LIBRARY_PATH use ldd <name_of_your_binary>
As to why the newline is required I can only speculate that it flushes the output buffer.
See also Why does printf not flush after the call unless a newline is in the format string?