如何在ARM汇编中用函数或其他方法消除重复代码?
Absolutely! You’re absolutely right to spot the duplication here—both GetCharAtR1 and GetCharAtR2 share identical core logic: finding a valid alphabetic character (A-z) and converting it to lowercase, with only minor differences in which registers are used and whether the index increments or decrements. We can eliminate this repetition with two common assembly techniques: reusable subroutines or assembly macros.
Option 1: Reusable Subroutine (Function)
This approach wraps the shared logic in a callable subroutine, using registers to pass parameters and return results. It’s great for keeping your code DRY (Don’t Repeat Yourself) and is ideal if you might need this logic in more places later.
Step 1: Define the Generic Subroutine
; Subroutine: FindValidLowerChar ; Inputs: ; r0: Base address of the string ; r1: Starting index (will be updated to the valid character's index) ; r2: Step size (+1 for forward search, -1 for backward search) ; Outputs: ; r1: Index of the first valid alphabetic character ; r3: Character converted to lowercase ; Notes: Follow ARM calling conventions if needed (save/restore registers as required) FindValidLowerChar ; Load current character from the string LDRB r3, [r0, r1] ; Skip characters below 'A' (non-alphabetic) CMP r3, #'A' ADDLT r1, r2 BLT FindValidLowerChar ; Skip characters above 'z' (non-alphabetic) CMP r3, #'z' ADDGT r1, r2 BGT FindValidLowerChar ; Convert uppercase to lowercase if needed CMP r3, #'a' ADDLT r3, #toLower ; Return to caller BX LR
Step 2: Call the Subroutine for Both Scenarios
Now replace your original GetCharAtR1 and GetCharAtR2 with calls to this subroutine, adapting register usage to match your original logic:
; Equivalent to original GetCharAtR1 GetCharAtR1 MOV r2, #1 ; Set step to +1 (forward search) BL FindValidLowerChar ; r1 is updated, r3 holds lowercase character ; Continue with your logic using r1 and r3 ; Equivalent to original GetCharAtR2 GetCharAtR2 ; Save registers if needed (follow your system's calling convention) PUSH {r1, r4, LR} MOV r1, r2 ; Pass r2 (original index) as subroutine's r1 MOV r2, #-1 ; Set step to -1 (backward search) BL FindValidLowerChar MOV r2, r1 ; Update original index register r2 MOV r4, r3 ; Store lowercase character in original r4 ; Restore saved registers and return POP {r1, r4, PC}
Option 2: Assembly Macro
If you want to avoid the small overhead of subroutine calls (like BL/BX instructions), use an assembly macro. Macros expand directly into your code at assembly time, so there’s no runtime cost—perfect for short, repeated logic.
Step 1: Define the Macro
; Macro: FIND_AND_LOWER_CHAR ; Parameters: ; base_reg: Register holding the string base address ; idx_reg: Register holding the current index (will be updated) ; char_reg: Register to store the found character (lowercase) ; step: Step size (+1 or -1) .macro FIND_AND_LOWER_CHAR base_reg, idx_reg, char_reg, step ; Local label (the "1b" syntax jumps back to the nearest label named 1) 1: LDRB \char_reg, [\base_reg, \idx_reg] ; Skip non-alphabetic characters below 'A' CMP \char_reg, #'A' ADDLT \idx_reg, #\step BLT 1b ; Skip non-alphabetic characters above 'z' CMP \char_reg, #'z' ADDGT \idx_reg, #\step BGT 1b ; Convert to lowercase if needed CMP \char_reg, #'a' ADDLT \char_reg, #toLower .endm
Step 2: Use the Macro in Your Code
Replace the original duplicate blocks with macro calls:
; Equivalent to original GetCharAtR1 GetCharAtR1 FIND_AND_LOWER_CHAR r0, r1, r3, 1 ; Equivalent to original GetCharAtR2 GetCharAtR2 FIND_AND_LOWER_CHAR r0, r2, r4, -1
Which Option to Choose?
- Subroutines: Better for larger, more complex logic that you might reuse across multiple parts of your code. They keep your code organized but add a tiny runtime overhead.
- Macros: Ideal for short, repetitive code snippets where you want to avoid subroutine call costs. They expand inline, so the final machine code is identical to your original duplicated blocks—but you only maintain one copy of the logic.
Both approaches will eliminate the duplication while preserving exactly the functionality you had before!
内容的提问来源于stack exchange,提问作者Ronit sharma

