0

I am working with ARM Assembly. I want to reverse a string, so if you pass the string "abcdefg", it will change the string to "gfedcba".

Essentially, this assembly code should be an implementation of:

void reversing(char *strn);

My line of thinking is that I have to keep a pointer to each string end. Then I would simply increment one and then decrement the other.

reversing:
    stmfd sp!,{r4-r8,lr}    @ Push to stack

    @ Solution here

    ldmfd sp!,{r4-r8,lr}    @ Pop from stack
    bx lr                   @ return

I am not sure the actual method to implement this into assembly code, so any suggestions would be great.


Attempted Solution:

reversing:
    stmfd sp!,{r4-r8,lr}    @ push to stack

    mov r5, #0          @ r5 = 0, beginning
    b my_strlen         @ get r4 = strlen
next:

loop:
    ldrb r6, [r0]       @ Get char string

    @ Not too sure about this part.
    strb r7, [r5]
    add r5, #1
    sub r4, #1

    cmp r4, r5
    bhi loop

end_reverse:
    ldmfd sp!,{r4-r8,lr}   
    bx lr           @ return




@
@ strlen function
@
my_strlen:
    @ Register usage:
    @ r0: string pointer
    @ r4: counter
    mov r4,#0       @ zero the counter

counter:
    ldrb r2,[r0]    @ Get character string
    movs r2,r2      @ Set flags
    beq strlen_done

    add r4,#1       @ Count the letter
    add r0,#1       @ Advance to the next character
    b counter       @ Loop back

strlen_done:
    b next 
  • You could just iterate through the string, pushing characters on to the stack, then pop them off. You have a lot of the code you need for that already. – Colin Feb 20 '18 at 15:29
  • @Colin__s , I was thinking of doing something like that. I'm just not sure how to actually implement the code because I'm stuck on iterating through the string. – An Unsullied Feb 20 '18 at 15:32
  • When you enter the function, the string pointer is in `r0`, load that into a register, compare it with 0, and increment it, keep doing that until it is 0, that's the end of the string. – Colin Feb 20 '18 at 15:36
  • @Colin__s , so to reverse the string, I would have to first load the string to a register, increment backwards, and then save it by popping it? – An Unsullied Feb 20 '18 at 15:39
  • Yes, you would have to keep pushing characters onto the stack while they're not 0, then pop them back off to the original string pointer. – Colin Feb 20 '18 at 15:40
  • @Colin__s, give me a few minutes - I will try to implement this. I may take a while, since I am a bit new to ARM assembly. When I finish, do you mind taking a look at it? – An Unsullied Feb 20 '18 at 15:42
  • @Colin__s , I have edited my post. Could you take a look at it and see if this is correct? I am getting a segmentation fault. – An Unsullied Feb 20 '18 at 15:54
  • @Colin__s: it's easy to reverse a string in-place with pointers to the start/end that meet in the middle. To use push/pop, you have to do zero-extending byte loads, so you expand the string by 4 onto the stack. (`ldr` loads four bytes, so IIRC you need `ldrb`) – Peter Cordes Feb 20 '18 at 16:00
  • @AnUnsullied: use a debugger to step through your code. Notice that `ldr r0, [r4]` is outside your loop, and that you're comparing the *pointer* against 0, not the character. (And you're loading / storing 4 bytes at a time, so you won't find the terminating 0 byte unless you fix that, too.) – Peter Cordes Feb 20 '18 at 16:02
  • @PeterCordes , Thank you - I should've used ldrb, rather than ldr. In addition, how do you reverse a string with pointers at the start/end? I am not sure how to implement this within ARM Assembly. – An Unsullied Feb 20 '18 at 16:04
  • @PeterCordes I am still getting a segmentation fault, even with ldrb r0, [r4] within the loop. Any ideas? Edit: It's probably because I'm comparing the pointer against 0, so how do I get it to compare against the character? Would it be ldrb r0, [r4, #0] or something like that? – An Unsullied Feb 20 '18 at 16:07
  • You have the char value in `r0` after the load, so use `cmp r0, #0` / `bne loop` as the bottom of your loop. (You want to copy the terminating 0 byte, so don't leave the loop until after storing it. A `do{}(while()` structure works perfectly here, and is more natural / idiomatic anyway. https://stackoverflow.com/questions/47783926/why-are-loops-always-compiled-like-this) – Peter Cordes Feb 20 '18 at 16:13
  • I think you've misunderstood ARM syntax, because it looks like the rest of your code is using `r0` as the pointer (which is normal; that's the first function arg), but your load/store are backwards. The part inside the `[]` is the address. – Peter Cordes Feb 20 '18 at 16:15
  • @PeterCordes, that makes sense, I definitely misunderstood the ARM syntax. I also haven't done a do{}(while()) structure within ARM before, so I am hoping to not use it for this experiment. In addition, when I tried running the code with 'abc' as an input, the result is simply 'a'. So I guess this means my iteration is incorrect? – An Unsullied Feb 20 '18 at 16:20
  • Your loop will be a lot easier if you put the loop-exit branch at the bottom. You always need to copy at least one character (because the empty string is one byte long). Whether you do that with `cmp` / `beq out_of_loop` right before a `b loop`, or whether you do it with the more straighforward `cmp r4,#0` / `bne loop`, it's the same difference. If you insist on putting the conditional branch at the top of the loop, you need to peel the first iteration or add extra code to null-terminate the destination string, or something. Don't fear the `do{}while()`, it's how loops *should* look in asm. – Peter Cordes Feb 20 '18 at 16:54
  • I've just realized that I needed to use strb rather than str since this is a string. However, my new solution simply iterates in order, rather than reversing it. (So 'abc' is still 'abc'). Any suggestions, @PeterCordes ? – An Unsullied Feb 20 '18 at 16:55
  • If you need to reverse in place, find the end of the string and then use a start and end pointer that meet in the middle. It should be easy to google examples of C code that reverses a string in-place with 2 pointers. Implement that algorithm in asm, comparing the pointers against each other with `cmp` / `bhi` to leave the loop when `start < end` isn't true anymore. – Peter Cordes Feb 20 '18 at 16:58
  • I see - I've removed the initial condition, and have the cmp / bne at the bottom of the loop. I also changed str to strb. However, I am now getting a segmentation fault. Any ideas why? – An Unsullied Feb 20 '18 at 16:58
  • @PeterCordes, I can't seem to figure out how to get a start and end pointer in assembly. I found this one: https://helloacm.com/reverse-string-in-cc/ under in-place reverse, and I can't seem to implement that in asm. – An Unsullied Feb 20 '18 at 17:50
  • If the caller doesn't give you an explicit length, you'd have to loop to find the end, *before* the reverse loop. (i.e. implement `strlen` as the first part of your function). That's what `while(*q++) ;` is doing in the link you found. – Peter Cordes Feb 20 '18 at 17:52
  • @PeterCordes, Yup, I figured the while(*q++) meant strlen, so I implemented that. I am just confused as to how to do the inside part of the while q > p of that function. I have edited the function above if you have a chance to look at it. – An Unsullied Feb 20 '18 at 18:00
  • My recommended technique here is write it in C, and then disassemble it. Even seems recommended by Arm engineers: https://community.arm.com/processors/b/blog/posts/how-do-i-do-x-in-assembler – solidpixel Feb 21 '18 at 22:30

0 Answers0