1

SORRY if i make you confuse about the question, but i don't know a better to describe it

i'm trying to write a NASM program to reverse a string in place.

i have 3 function: strlen, readstring, and asm_main

readstring: read from user input and store it in reserved space "inputstring"

    push ebp        ; setup routine
    mov ebp, esp
    ;;;;;;;;;;;;;;;;;;;;;;;;;; 
    mov eax, message
    call print_string   ; print"please enter your string message"

    mov eax, 3  ; read
    mov ebx, 1  ; from standard input
    mov ecx,inputstring;  store at memory locaton inputstring
    mov edx, 100        ; 100 byte
    int 0x80

    mov eax, inputstring

   ;;;;;;;;;;;;;;;;;;;;;
    pop ebp
    ret

Later, i use another subprogram "strlen" to get the length of users' input

The problem is:

In my main program, i have two register hold the address of the beginning and the last char. so ecx holds begin, ebx holds last char

let's say i type "abcde",

so i have $ecx point to the beginning of the string, and $ebx point to the last char(which is e\n). My question is, when i swaping ecx and ebx, am i swapping the whole string(abcde) with the last char(e/n)?

or am i swaping the first char(a) with the last char(e/n)?

when i try to print out the content of each register in GDB.

ecx: abede/n

ebx: e/n

so i'm swaping the whole string with the last char, which is definitely not i want. So where did i do wrong??? can someone pls give me a hint?

Here is my code

%include "asm_io.inc"
segment .data
message db "Please enter your string message: ", 0xA,0
formatin db "%d", 0xA


segment .bss
   inputstring: resb 100

segment .text
    global asm_main
    extern printf
    extern scanf


**asm_main**:
    enter 0, 0
    pusha

    ;;;;;;;;;;;;;;;;;;;;;;;;
    call readstring
    mov ecx, eax    ; now ecx contains the begin address
    call strlen     ; when return, eax will hold the length

    push eax        ; we need eax in the loop

    ; use edi as temporary pointer
    ; use ebx to point to the last char

    mov ebx, 0    ;initialize ebx to 0
    add ebx, ecx  ; ebx = ecx now, ebx points to the beginning
    add ebx, eax  ; ebx = ecx + eax, now it points to then end
    sub ebx, 1    ; ebx = ecx +eax -1, now it points to the 
                  ; last char

while:
    cmp ebx, ecx   ; cmp end , begining
    jle exitWhile

    mov edi, [ebx]    ; temp = *end
    mov eax,[ecx]   ; *end = *begining
    mov [ebx], eax
    mov [ecx], edi    ; *beginning = temp

    inc ecx
    dec ebx

    jmp while

exitWhile:

    pop eax
    popa
    mov eax, 0
    leave           ; missing this line will cause segmentation 
                    ; fault, why?
    ret

**readstring**:
    push ebp        ; setup routine
    mov ebp, esp
    ;;;;;;;;;;;;;;;;;;;;;;;;;; 
    mov eax, message
    call print_string

    mov eax, 3  ; read
    mov ebx, 1  ; from standard input
    mov ecx,inputstring;  store at memory locaton inputstring
    mov edx, 100        ; 100 byte
    int 0x80

    mov eax, inputstring

   ;;;;;;;;;;;;;;;;;;;;;
    pop ebp
    ret


**strlen**:
    push ebp
    mov ebp, esp

    push esi
    ;;;;;;;;;;;;;;;;;;;;;
    mov esi, ecx    ; now esi contains the address of string
    mov edx, 0     ;  edx will be int i
loop:
    mov al, [esi]   ; al 
    cmp al, 0xA     ; check if al holds an ASCII new line
    je  exitLoop

    inc esi
    inc edx

    cmp esi, inputstring+100; see if esi is pointing past the end
                    ; of the 100 reserved byte

    jl loop


exitLoop:
    ;;;;;;;;;;;;;;;;;;;;
    mov eax, edx
    pop esi
    pop ebp
    ret
齐天大圣
  • 1,169
  • 5
  • 15
  • 36
  • Ok... I've read that three times and I'm still not sure what it is that you are actually trying to achieve. I understand what you are saying is wrong, but what is your goal? What do you -expect- the code to do? – David Hoelzer Feb 08 '15 at 21:20
  • @Sorry about that. I'm try to reverse a string in place. let me edit my question first – 齐天大圣 Feb 08 '15 at 21:21
  • An address is always an address to one specific memory location, not a range or memory locations. The `ecx` register contains the address to the first character in the string, not the whole string. – Guffa Feb 08 '15 at 21:23
  • @DavidHoelzer I edited my question, hope that will make it clear – 齐天大圣 Feb 08 '15 at 21:28
  • You are playing around with the registers eax, ebx and so on in the CPU. That does not affect the String itself you saved at the starting address "inputstring", When you enter "abcd", inputstring will point to "a", inputstring+1 to "b", inputstring+2 to "c" and so on. Every Address points to single byte. If you want to reverse the string in memory, you could create another memory location called "outputstring" and try to make a code which copys the reverse inputstring into outputstring. Lets say your string is 4 bytes long: mov eax, [inputstring+3]; mov [outputstring], eax; and so on. – Welcor Feb 08 '15 at 22:01
  • @Blechdose Thank you very much. I appreciate it. But i'm supposed to reverse it in place so I'm not allow to use extra memory. – 齐天大圣 Feb 08 '15 at 23:25
  • The "last character" - `e\n` - is two characters. You probably don't want to swap the `\n`, so don't forget to account for that. – Frank Kotler Feb 09 '15 at 01:29
  • Okay, I just looked again at your code - you do account for the linefeed. But in your "swap" routine, you're swapping four bytes at once. Use just an 8 bit register here. – Frank Kotler Feb 09 '15 at 01:42

1 Answers1

0

You are swapping four characters at a time since you are using 32-bit registers for the job. You swap "abcd" with "e\n??" (where ?? are the two bytes after your string). Use an 8-bit register for ASCII characters:

while:
  cmp ebx, ecx      ; cmp end , beginning
  jbe exitWhile     ; while (end > start) {

  mov al,[ebx]
  xchg al,[ecx]         ; extremely slow: atomic RMW + full memory barrier
  mov [ebx],al

  inc ecx
  dec ebx

  jmp while        ; }

exitWhile:
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Fabel
  • 1,711
  • 14
  • 36
  • 1
    Pointer compares should use `jbe` not `jle`. An array can span the 2GiB boundary between low and high half of virtual address space (so signed overflow is possible when incrementing a pointer within an array), but not wrap around the end of memory. See also [Should pointer comparisons be signed or unsigned in 64-bit x86?](https://stackoverflow.com/q/47687805) re: x86-64 where there's a hole in the middle, unlike for 32-bit mode. (edited to fix this for you) – Peter Cordes Apr 20 '22 at 03:02