簡體   English   中英

將C代碼轉換為ARM Cortex M3匯編代碼

[英]Convert C-code to ARM Cortex M3 Assembler Code

我有以下C函數

int main_compare (int nbytes, char *pmem1, char *pmem2){
    for(nbytes--; nbytes>=0; nbytes--) {    
        if(*(pmem1+nbytes) - *(pmem2+nbytes) != 0) {
            return 0;
        }
    }
    return 1;
}

我想將其轉換為ARM-Cortex M3-匯編代碼。 我不是很擅長此事,而且我沒有合適的編譯器來測試我是否做對了。 但是我到目前為止所擁有的

byte_cmp_loop PROC
; assuming: r0 = nbytes, r1=pmem1, r2 = pmem2

    SUB R0, R0, #1    ; nBytes - 1 as maximal value for loop counter

_for_loop: 
    ADD R3, R1, R0    ;
    ADD R4, R2, R0    ; calculate pmem + n
    LDRB R3, [R3]     ;
    LDRB R4, [R4]     ; look at this address

    CMP R3, R4        ; if cmp = 0, then jump over return

    BE _next          ; if statement by "branch"-cmd
        MOV R0, #0    ; return value is zero
        BX LR         ; always return 0 here
_next:

    sub R0, R0, #1    ; loop counting
    BLPL _for_loop    ; pl = if positive or zero

    MOV R0, #1        ;
    BX LR             ; always return 1 here

ENDP

但是我真的不確定這是否正確,但是我不知道如何檢查...。

我在那里僅看到3個相當簡單的問題:

BE _next          ; if statement by "branch"-cmd
...
sub R0, R0, #1    ; loop counting
BLPL _for_loop    ; pl = if positive or zero
  • BEQ而非BE條件代碼始終為2個字母。
  • SUB本身不會更新標志-您需要使用后綴來表示SUBS
  • BLPL將分支和鏈接,從而覆蓋您的BLPL地址-您需要BPL 實際上, BLPL不會在這里進行匯編,因為在Thumb中,有條件的BL需要IT來設置(除非您的匯編器足夠聰明,可以自動插入一個)。

編輯:在原始代碼和下面的示例中, R4的使用當然也存在更普遍的問題-如果與C代碼接口,則必須在函數調用中保留原始值,然后R0還原( R0 - R3是指定的參數/臨時寄存器,可以自由修改)。 如果您使用的是純匯編語言,則不必遵循標准的調用約定,因此可以更加靈活。


現在,這是C代碼的非常直觀的表示,並且沒有充分利用指令集-尤其是索引尋址模式。 匯編編程的吸引力之一就是可以完全控制指令,那么如何使它值得我們花點時間呢?

首先,讓我們使C代碼看起來更像我們想要的程序集:

int main_compare (int nbytes, char *pmem1, char *pmem2){
    while(nbytes-- > 0) {    
        if(*pmem1++ != *pmem2++) {
            return 0;
        }
    }
    return 1;
}

現在,這更清楚地顯示了我們的意圖,讓我們玩一下編譯器:

byte_cmp_loop PROC
; assuming: r0 = nbytes, r1=pmem1, r2 = pmem2

_loop:
    SUBS R0, R0, #1   ; Decrement nbytes and set flags based on the result
    BMI  _finished    ; If nbytes is now negative, it was 0, so we're done

    LDRB R3, [R1], #1 ; Load from the address in R1, then add 1 to R1
    LDRB R4, [R2], #1 ; ditto for R2
    CMP R3, R4        ; If they match...
    BEQ _loop         ; then continue round the loop

    MOV R0, #0        ; else give up and return zero
    BX LR

_finished:
    MOV R0, #1        ; Success!
    BX LR
ENDP

指令減少了將近25%! 現在,如果我們引入另一個指令集功能-條件執行-並在不破壞C語義的情況下稍微放寬了要求,則它會變得更小:

byte_cmp_loop PROC
; assuming: r0 = nbytes, r1=pmem1, r2 = pmem2

_loop:
    SUBS R0, R0, #1 ; In C zero is false and any nonzero value is true, so
                    ; when R0 becomes -1 to trigger this branch, we can just
                    ; return that to indicate success
    IT MI           ; Make the following instruction conditional on 'minus'
    BXMI LR

    LDRB R3, [R1], #1
    LDRB R4, [R2], #1
    CMP R3, R4
    BEQ _loop

    MOVS R0, #0     ; Using MOVS rather than MOV to get a 16-bit encoding,
                    ; since updating the flags won't matter at this point
    BX LR
ENDP

組裝成微薄的22個字節,比我們從:D開始的代碼少40%

好吧,這是一些編譯器生成的代碼

arm-none-eabi-gcc -O2 -mthumb -c test.c -o test.o
arm-none-eabi-objdump -D test.o

00000000 <main_compare>:
   0:   b510        push    {r4, lr}
   2:   3801        subs    r0, #1
   4:   d502        bpl.n   c <main_compare+0xc>
   6:   e007        b.n 18 <main_compare+0x18>
   8:   3801        subs    r0, #1
   a:   d305        bcc.n   18 <main_compare+0x18>
   c:   5c0c        ldrb    r4, [r1, r0]
   e:   5c13        ldrb    r3, [r2, r0]
  10:   429c        cmp r4, r3
  12:   d0f9        beq.n   8 <main_compare+0x8>
  14:   2000        movs    r0, #0
  16:   e000        b.n 1a <main_compare+0x1a>
  18:   2001        movs    r0, #1
  1a:   bc10        pop {r4}
  1c:   bc02        pop {r1}
  1e:   4708        bx  r1

arm-none-eabi-gcc -O2 -mthumb -mcpu=cortex-m3 -c test.c -o test.o
arm-none-eabi-objdump -D test.o

00000000 <main_compare>:
   0:   3801        subs    r0, #1
   2:   b410        push    {r4}
   4:   d503        bpl.n   e <main_compare+0xe>
   6:   e00a        b.n 1e <main_compare+0x1e>
   8:   f110 30ff   adds.w  r0, r0, #4294967295 ; 0xffffffff
   c:   d307        bcc.n   1e <main_compare+0x1e>
   e:   5c0c        ldrb    r4, [r1, r0]
  10:   5c13        ldrb    r3, [r2, r0]
  12:   429c        cmp r4, r3
  14:   d0f8        beq.n   8 <main_compare+0x8>
  16:   2000        movs    r0, #0
  18:   f85d 4b04   ldr.w   r4, [sp], #4
  1c:   4770        bx  lr
  1e:   2001        movs    r0, #1
  20:   f85d 4b04   ldr.w   r4, [sp], #4
  24:   4770        bx  lr
  26:   bf00        nop

有趣的是thumb2擴展確實並沒有使它變得更好,甚至可能更糟。

如果您沒有編譯器,是否意味着您也沒有匯編器和鏈接器? 如果沒有匯編器和鏈接器,我將需要大量工作來手工編譯和匯編機器代碼。 然后,如何將其加載到處理器等中?

如果您沒有arm的交叉編譯器,那么您根本沒有編譯器嗎? 您需要告訴我們有關您做什么和不做什么的更多信息。 如果您擁有用於查找堆棧溢出並發布問題的Web瀏覽器,則可能可以下載代碼源工具或https://launchpad.net/gcc-arm-embedded工具,並具有編譯器,匯編器和鏈接器(並且沒有將c轉換為asm)。

就您的代碼而言,對nbytes減去1是正確的,但是您無法將該nbytes值與零進行比較,以查看是否根本不需要執行任何操作。

用偽代碼

if nbytes >= 0 return 1
nbytes--;
add pmem1+nbytes
load [pmem1+nbytes]
add pmem2+nbytes
load [pmem2+nbytes]
subtract
compare with zero
and so on

您直接進入了nbytes -而不是if nbytes> = 0; 比較。

如果等於的分支程序集是BEQ而不是BE和BPL而不是BLPL。 因此,請解決這些問題,一開始就對_next進行無條件分支,我想就是對它進行了編碼。

byte_cmp_loop PROC
; assuming: r0 = nbytes, r1=pmem1, r2 = pmem2

    B _next

_for_loop: 
    ADD R3, R1, R0    ;
    ADD R4, R2, R0    ; calculate pmem + n
    LDRB R3, [R3]     ;
    LDRB R4, [R4]     ; look at this address

    CMP R3, R4        ; if cmp = 0, then jump over return

    BEQ _next          ; if statement by "branch"-cmd
        MOV R0, #0    ; return value is zero
        BX LR         ; always return 0 here
_next:

    sub R0, R0, #1    ; loop counting
    BPL _for_loop    ; pl = if positive or zero

    MOV R0, #1        ;
    BX LR             ; always return 1 here

ENDP

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM