You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在ARM汇编中用函数或其他方法消除重复代码?

Refactoring Duplicate ARM Assembly Code for Character Lookup

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 19:52:48