assemblyx86x86-64att

Iterating through string stored in register in assembly x86 (asm)


Say if I have a very long string whose address is stored in rdi, is there anyway I can iterate through every character of the string?

This is what I tried so far, but it's very inefficient and I still need to create a separate method to find the length of the string to terminate the loop. Is there a better method for this asm x86-64? I've only found this one) so far but here my string is only stored in a register and cannot be defined at the start.

Assume that before function, the pointer to the string is already moved to %rdi:


.global function

test:       .asciz "\nTest:`%c"

function:

pushq   %rbp
movq    %rsp, %rbp

pushq   %rdi
pushq   %rdi
movq    (%rdi)  %rax
movq    $0, %rbx
movq    $8, %rdx
pushq   %rax
pushq   %rbx

loop:
movzb   %al, %rcx
movq    %rcx, %rsi
movq    $test, %rdi
call    printf
movq    (%rsp), %rbx
movq    8(%rsp), %rax
movq    $8, %rdx
shr $8, %rax
incq    %rbx
cmpq    %rbx,%rdx
jne loop

next_byte:
add $8, %rdi
movq    (%rdi), %rax
movq    $0, %rbx
pushq   %rcx
pushq   %rdx
pushq   %rax
pushq   %rbx
jmp loop

movq    %rbp, %rsp
popq    %rbp
ret

Solution

  • That's very confusing code. Why does it have tons of pushes? Why do you load 8 bytes at a time instead of going byte by byte? Why do you move stuff around unnecessarily? Is your string zero terminated? You could do:

    function:
        push %rbx              # save a call-preserved register
        mov %rdi, %rbx         # use it to save the current position across calls
    loop:                      # while(1) {
        movzbl (%rbx), %esi       # zero-extending byte load
        test %esi, %esi
        jz done                   # if (*ptr == 0) break;
    
        lea test(%rip), %rdi
        xor %eax, %eax            # AL = 0 args in XMM regs
        call printf@plt           # printf("Test: %c", *ptr)
    
        inc %rbx                  # ptr++
        jmp loop               # }
    done:
        pop    %rbx            # restore the caller's reg we saved earlier
        ret