0

I try to write a program in arm assembly, which writes whole char** argv content. In C it would be like so:

#include <stdio.h>

int main(int argc, char** argv) {
    for (unsigned int i = 0; argv[i] != 0; i++)
        puts(argv[i]);
    return 0;
}

and I wrote it in assembly like this:


.global main

.data

.bss

.text

.align 4

@r0 = argc
@r1 = argv

main:
        @prologue
        stmfd sp!, {fp, lr}
        add fp, sp, #4
        sub sp, sp, #8

        @i = 0
        mov r0, #0
        str r0, [fp, #-8]
        b loop_begin

loop_content:
        bl puts
        ldr r0, [fp, #-8]
        add r0, r0, #1
        str r0, [fp, #-8]

loop_begin:
        @r0 = i
        ldr r0, [fp, #-8]

        @i = i * 4
        lsl r0, r0, #2

        @r0 = argv + i
        add r0, r1, r0

        @r3 = argv[i]
        ldr r0, [r0]

        @argv[i] == 0?
        cmp r0, #0

        @if arvg[i] != 0 go to ...
        bne loop_content

        mov r0, #0
        sub sp, fp, #4
        ldmfd sp!, {fp, lr}
        bx lr

but it gives me segfault at

        str r0, [fp, #-8]

I have no idea why, do you have any ideas why does it happen?

Ivan
  • 316
  • 3
  • 15
  • @Afshin, I am going to use this code for `char** envp` too, so this condition is more unique :) – Ivan Dec 10 '19 at 17:47
  • Are you sure that's where the segfault happens? Which line, as you have multiple such instructions? – Jester Dec 10 '19 at 17:57
  • @Jester, yeah, I tried to debug it with gdb, so it happens exactly at this string – Ivan Dec 10 '19 at 18:03
  • I have tried to use r9 instead of local variable, now the problem is the same, but the error happens at `add r9, r9, #1`, right after the `bl puts`, due to this I think `bl puts` can cause the error, but there are no obvious reasons why – Ivan Dec 10 '19 at 18:04
  • That `add` can not possibly fault. You likely used gdb wrong. There are problems in your code, such as relying on the value in `r1` being preserved across calls. Indeed, just fixing that makes it work for me. – Jester Dec 10 '19 at 18:09
  • @Jester, can you, please, explain, what is the problem with `r1`? – Ivan Dec 10 '19 at 18:16
  • 2
    It's a caller-saved register. `bl puts` will destroy it. You will need to preserve it yourself. – Jester Dec 10 '19 at 18:24
  • @Jester, holy registers... i added `mov r1, r8` before the call and `mov r8, r1` right after and it helped! Thanks a lot! You can answer the question so I can mark it as a right answer – Ivan Dec 10 '19 at 18:29
  • 1
    Note you can't just abuse callee-saved registers without saving them even if it seems to work. The same reason `bl puts` preserves `r8` for you, you also must preserve it for your caller (the libc code in this case). – Jester Dec 10 '19 at 18:36
  • @Jester, thanks for the advice :) – Ivan Dec 10 '19 at 18:42
  • @Afshin: `argv[]` is a NULL-terminated array of pointers. (`argv[argc] == NULL`) The C code is safe. – Peter Cordes Dec 11 '19 at 02:36

0 Answers0