如何在TASM中通过字符串操作实现用户输入字符串的逆序存储与显示
pushf/popf for Flag Preservation) Perfect, let's tackle this exactly how you want it—using string operations, preserving the flag register with pushf/popf, and avoiding alternative methods like manual array indexing. Here's a step-by-step breakdown and implementation:
Key Background
First, a quick recap to align with your knowledge:
stdsets the Direction Flag (DF) to 1, making string instructions traverse memory from high to low addresses (ESI/EDI automatically decrement after each operation).cldsets DF to 0 for forward traversal (ESI/EDI increment).- We use
pushfbeforestdto save the current EFLAGS register (including the original DF state), thenpopfafterward to restore it—critical to avoid breaking any subsequent code that relies on the original direction setting.
Implementation (NASM Syntax, Linux x86)
Let's write a complete example that takes an input string, reverses it to an uninitialized variable, and prints the result:
section .data input_str db "Hello, Stack Overflow!", 0 ; Example input string (C-style null-terminated) str_len equ $ - input_str - 1 ; Length of the string (exclude null terminator) section .bss rev_str resb str_len ; Uninitialized variable to store reversed string section .text global _start _start: ; 1. Save the original flag register state (critical for restoring DF later) pushf ; 2. Set direction flag to reverse traversal std ; 3. Set up source and destination pointers lea esi, [input_str + str_len - 1] ; ESI = last character of input string (e.g., "!") lea edi, [rev_str + str_len - 1] ; EDI = last byte of the uninitialized rev_str mov ecx, str_len ; ECX = number of characters to copy ; 4. Reverse the string with a single string operation rep movsb ; Automatically copies ECX bytes: ; - Each copy: [EDI] = [ESI] ; - ESI and EDI decrement each time (thanks to std) ; 5. Restore the original flag register (resets DF to its initial state) popf ; 6. Print the reversed string (Linux syscall) mov eax, 4 ; sys_write mov ebx, 1 ; stdout file descriptor lea ecx, [rev_str] ; pointer to reversed string mov edx, str_len ; length of string to print int 0x80 ; Exit the program mov eax, 1 ; sys_exit xor ebx, ebx ; exit code 0 int 0x80
How It Works
Let's walk through the core logic with the example input "Hello, Stack Overflow!":
- Flag Preservation:
pushfsaves the current EFLAGS to the stack—this ensures we don't leave DF set to 1 for any code that runs after this routine. - Reverse Traversal Setup:
stdtells string instructions to work backward. We point ESI to the last character of the input (!) and EDI to the last byte ofrev_str. - String Copy:
rep movsbrepeats the move operationstr_lentimes. Each iteration copies the byte at ESI to EDI, then decrements both registers. This effectively copies the input string from end to start intorev_strfrom end to start—resulting in a fully reversed string inrev_str. - Flag Restoration:
popfpulls the original EFLAGS back from the stack, resetting DF to whatever it was before we ranstd.
Alternative: Manual Loop with lodsb/stosb
If you prefer to handle each character explicitly (instead of rep movsb), here's a modified loop version:
; Replace the rep movsb section with this: reverse_loop: lodsb ; AL = [ESI], then ESI-- (due to std) stosb ; [EDI] = AL, then EDI-- loop reverse_loop ; Decrement ECX, loop until ECX = 0
Note that for this to work, EDI still needs to start at rev_str + str_len - 1—each stosb will place the character in the next lower address of rev_str, building the reversed string correctly.
Critical Notes
- Always calculate the string length correctly: For C-style null-terminated strings, subtract 1 to exclude the
0terminator. - The
pushf/popfpair is non-negotiable if your program has other string operations later—leaving DF set to 1 will break any forward-traversing string instructions (like those usingcld).
内容的提问来源于stack exchange,提问作者King0fChaos97

