Does int 0x80 overwrite register values?

64-bit, assembly, gdb, linux, nasm

Solution

`int 0x80` just causes a software interrupt. In your case it's being used to make a system call. Whether or not any registers are affected will depend on the particular system call you're invoking and the system call calling convention of your platform. Read your documentation for the details.

Specifically, from the System V Application Binary Interface x86-64™ Architecture Processor Supplement [PDF link], Appendix A, x86-64 Linux Kernel Conventions:

The interface between the C library and the Linux kernel is the same as for the user-level applications...

For user-level applications, `r8` is a scratch register, which means it's caller-saved. If you want it to be preserved over the system call, you'll need to do it yourself.

Problem

I wrote a program which is supposed to behave like a for while loop, printing a string of text a certain number of times. Here is the code: ``` global _start section .data msg db "Hello World!",10 ; define the message msgl equ $ - msg ; define message length ; use minimal size of storage space imax dd 0x00001000 ; defines imax to be big! section .text _start: mov r8, 0x10 ; <s> put imax in r8d, this will be our 'i' </s> ; just attempt 10 iterations _loop_entry: ; loop entry point mov eax, 4 ; setup the message to print mov ebx, 1 ; write, stdout, message, length mov ecx, msg mov edx, msgl int 0x80 ; print message ; this is valid because registers do not change dec r8 ; decrease i and jump on not zero cmp r8,1 ; compare values to jump jnz _loop_entry mov rax, 1 ; exit with zero mov rbx, 0 int 0x80 ``` The problem I have is the program runs into an infinite loop. I ran it inside gdb and the cause is: int 0x80 is called to print the message, and this works correctly, however after the interrupt finishes, the contents of r8 is set to zero, rather than the value it should be. r8 is where the counter sits, counting (down) the number of times the string is printed. Does int 0x80 modify register values? I noticed that rax, rbx, rcx, rdx were not affected in the same way. Test Results Answer: YES! It does modify r8. I have changed two things in my program. Firstly I now `cmp r8, 0`, to get Hello World! the correct number of times, and I have added ``` mov [i], r8 ; put away i ``` After `_loop_entry:` and also I have added ``` mov r8, [i] ; get i back ``` after the first `int 0x80`. Here is my now working program. More info to come on performance against C++. ``` ; ; main.asm ; ; ; To be used with main.asm, as a test to see if optimized c++ ; code can be beaten by me, writing a for / while loop myself. ; ; ; Absolute minimum code to be competative with asm. global _start section .data msg db "Hello World!",10 ; define the message msgl equ $ - msg ; define message length ; use minimal size of storage space imax dd 0x00001000 ; defines imax to be big! i dd 0x0 ; defines i section .text _start: mov r8, 0x10 ; put imax in r8d, this will be our 'i' _loop_entry: ; loop entry point mov [i], r8 ; put away i mov eax, 4 ; setup the message to print mov ebx, 1 ; write, stdout, message, length mov ecx, msg mov edx, msgl int 0x80 ; print message ; this is valid because registers do not change mov r8, [i] ; get i back dec r8 ; decrease i and jump on not zero cmp r8,0 ; compare values to jump jnz _loop_entry mov rax, 1 ; exit with zero mov rbx, 0 int 0x80 ```

Original source

Related problems