2014-01-24 4 views
2

я получил следующее кесарево функциюПреобразовать C-код ARM Cortex M3 ассемблере

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 

, но я действительно не уверен, если это правильно, но я понятия не имею, как проверить это ....

+0

В какой архитектуре вы намерены запустить этот код? Можете ли вы немного очистить свой код, будучи последовательным в отношении отступов и капитализации инструкций? –

+0

О, я забыл упомянуть архитектуру ...:/ это кора m3. – Faekynn

ответ

2

я вижу только 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 будет веткой и ссылкой, таким образом, переписывая ваш обратный адрес - вы хотите BPL. На самом деле, BLPL не собирался здесь, так как в Thumb условному BL понадобится IT, чтобы настроить его (если, конечно, ваш ассемблер достаточно умен, чтобы вставить его автоматически).

Edit: есть и, конечно, более общая проблема с использованием R4 как в исходном коде и моих примерах ниже - если вы взаимодействия с C кодом исходное значение должны быть сохранены по функции вызов и восстановление после этого (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 байт, это почти 40% меньше кода, чем мы начали: D

1

Ну, вот некоторые компилятор сгенерированный код

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 действительно не кажется, делают это лучше, возможно хуже.

Если у вас нет компилятора, значит, у вас нет ассемблера и линкера? Я без ассемблера и компоновщика будет много работы по сбору и сборке машинного кода. Тогда как вы собираетесь загружать это в процессор и т. Д.?

У меня есть симулятор большого пальца (не расширение большого пальца2, просто большой палец), который поможет вам изучить сборку большого пальца руки, чтобы начать, и ваш cortex-m3 также поддержит эти инструкции. поиск для thumbulator в github. если у вас нет кросс-компилятора для руки, у вас есть компилятор вообще? Вы должны рассказать нам больше о том, что вы делаете и чего нет. Если у вас есть веб-браузер, который вы использовали для поиска stackoverflow и отправки вопросов, вы, вероятно, можете загрузить инструменты для инструментов sourcery или инструменты https://launchpad.net/gcc-arm-embedded, а также иметь компилятор, ассемблер и компоновщик (и не нужно переводить конвертировать из c в asm).

Что касается вашего кода, то вычитание 1 верно для nbytes--, но вам не удалось сравнить это значение 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--, не делая при-байт> = 0; сравнение.

Сборка для ветви, если она равна BEQ not 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 
Смежные вопросы