0

so I ma trying to solve an exercise that changes the data in the even with odd positions in a string. My input string is in RDI, RSI is my output, and the input size is in RDX. I am not sure what I am doing wrong as I get plenty of errors when I try to run.

My logic: if number of odds equals number of evens, then I need to add odd, else add even. each time I add in the output, I then verify if number of odds+evens equals the input size. If yes, then I'm finished and I need to finish, else continue.

I am pretty new to this assembly stuff so if I wrote any stupid stuff, know that I am a big noob.

example : input string "airport" -> output string "iaprrot"

mov RCX, RDX
mov RCX, 0 ; keeping track of how many odd positions have been added to the output
mov RSP, 0 ; keeping track of how many evenpositions have been added to the output 

myloop:    
    cmp RSP, RCX 
    je odd
    cmp RCX, RSP
    jg even
    ret

even:
    sub RDI, 1 ; remained on odd position so need to go on the previous position
    inc RSP ; increment the number of even positions i managed
    mov AL, [RDI]
    mov [RSI], AL ; put in the output the character from the even position
    inc RSI
    add RDI, 2
    mov RAX, RCX 
    add RAX, RSP ; add number of odds with number of evens
    cmp RDX, RAX ; if  number of odds+evens is less then input size then repeat
    jg myloop
    ret

odd:
    inc RDI ; go on odd position
    inc RCX ; increment the number of odd position i managed
    mov AL, [RDI]
    mov [RSI], AL ; put in output the character from the odd position
    inc RSI
    mov RAX, RCX
    add RAX, RSP
    cmp RDX, RAX
    jg myloop
    ret
brewandrew
  • 156
  • 9
  • 1
    `rsp` is not a general purpose register. You may be able to treat it as such locally, but what was there on entry must be preserved, somehow, otherwise `ret` will go to a random place. – 500 - Internal Server Error May 07 '21 at 10:57
  • 1
    That issue aside, if you are free to use any method you like, my suggestion would be to read two characters at a time as long as there are two available, and then swap them, as in `mov AX, [RDI]; XCHG AL, AH; mov [RSI], AX`. – 500 - Internal Server Error May 07 '21 at 11:01
  • It would be vastly simpler to copy two bytes at once, swapping the pair. Look at how much logic you need to figure out exactly what to do with a single position. (Especially if you insist on inc/dec of registers instead of just using an offset in the addressing mode.) e.g. `movzx eax, word [rdi[` / `rol ax, 8` (swap AH and AL) / `mov [rsi], ax` – Peter Cordes May 07 '21 at 11:03
  • 1
    @500-InternalServerError Heh, we were both the same comment at the same time. But note that `rol ax, 8` is more efficient than `xchg`, especially if you want to read the AX afterward. (No partial-register merging needed.) – Peter Cordes May 07 '21 at 11:04
  • but what is wrong with my code/logic basically? I'm very trivial in this assembly stuff and so wouldn't know how to apply what you guys said. – brewandrew May 07 '21 at 11:11
  • I'm not sure anything *is* wrong with your logic, except for destroying the stack pointer so `ret` will try to pop a return address from an invalid pointer. Pick any other register, then use a debugger (GDB for example) to single-step your code. "plenty of errors" is not specific enough for a [mcve], so if you want other people to help debug, make sure you quote error messages, and/or exact results of what does happen, and what you see with a debugger. – Peter Cordes May 07 '21 at 11:19
  • no way, you were totally right with the RSP, that was the problem. But now I see it doesn't add the last character from the string. so like the output size is inputsize-1 – brewandrew May 07 '21 at 11:26
  • The problem with overwriting RSP is almost a duplicate of [Why are rbp and rsp called general purpose registers?](https://stackoverflow.com/q/36529449). If you want help debugging your messy logic for the final character, fix that bug (in the question) so it's not a distraction, and include that specific actual result in the question. Then ideally also update with what you find while single-stepping that last iteration. (Or maybe you'll notice on your own if something's wrong with your logic) – Peter Cordes May 07 '21 at 11:40
  • @500-InternalServerError: Even more efficient would be doing multiple pairs of bytes at once. e.g. `(x & 0x00ff00ff...) << 8 | ((x>>8) & 0x00ff00ff...)`. Up to 8 bytes at a time in scalar registers. Or get the masking for free with SSE2 (baseline for x86-64) `psrlw` / [`psllw`](https://www.felixcloutier.com/x86/psllw:pslld:psllq), doing 16 bytes at a time. (Or 8 or 4 with movq / movd loads/stores. Obviously even more efficient if you have SSSE3 `pshufb` to re-arrange byte in one instruction. – Peter Cordes May 07 '21 at 14:21
  • 1
    @thebalkandude: Where is the final byte supposed to come from, in odd-length strings? Are you supposed to copy the unpaired byte from the *same* position? Because copying from one byte later would mean you load the terminating 0 byte of the source string. If so, the final byte will need special handling whether you do it efficiently (1 pair at a time) or not. – Peter Cordes May 07 '21 at 14:24

0 Answers0