3

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
4

1 回答 1

5

int 0x80只会导致软件中断。在您的情况下,它被用于进行系统调用。是否有任何寄存器受到影响将取决于您正在调用的特定系统调用以及您平台的系统调用调用约定。阅读您的文档以了解详细信息。

具体来说,来自System V Application Binary Interface x86-64™ Architecture Processor Supplement [ PDF link ],附录 A,x86-64 Linux Kernel Conventions

C 库和 Linux 内核之间的接口与用户级应用程序的接口相同......

对于用户级应用程序,r8是一个临时寄存器,这意味着它是调用者保存的。如果您希望它通过系统调用保留,您需要自己做。

于 2013-07-25T22:47:56.567 回答