Skocz do zawartości

ARM Cortex-M dissasemblacja programu - pytanie o mnemonik i sens tych instrukcji


FlyingDutch

Pomocna odpowiedź

Cześć,

cały czas uczę się stosowania assemblera dla ARM Cortex-M. Coraz częściej w kompilatorze C włączam sobie okno dissasemblacji programu, aby zobaczyć jak wygląda kod w assemblerze ARM dla danego kodu programu w języku C. Dzisaj oglądałem sobie stray program (pisany jeszcze w Ride7_ARM-RKit). Poniżej zrzut ekranu z IDE z zaznaczonym oknem disasemblacji fragmentu programu:

DisAsm_01.thumb.png.83b73bd83b9d6e4b23b04d5b18a59628.png

Chodzi mi o mnemoniki "db" np. :

db	80h

Z tego co widzę te komendy pod danym adresem ustawiają bajt na wartość podaną w hex (w tym przypadku 0x80). W oknie dissasemblacji widzimy długi ciąg takich komend, zastanawiam się jaki ten ciąg komend db ma sens dla wykonania programu i jak one są interpretowane? Co prawda pred tymi instrukcjami jest instrukcja skoku (branch):

BX	LR

więc nie jeste na 100% pewien, że te instrukcje mają wpływ na wykonanie programu. Może ktoś potrafi mi to wytłumaczyć?

Pozdrawiam

Edytowano przez FlyingDutch
update
  • Lubię! 2
Link do komentarza
Share on other sites

(edytowany)

OK - zobacz na kod wykonującego się programu jaki dla Ciebie stworzyłem i na :

1. Okno debug:

ARM_CODE.thumb.jpg.d6fe0c7193813b16fb4c91d7215f038a.jpg

 

2. Disassemblację pliku wynikowego, co CubeIDE domyślnie tworzy plik z rozszerzeniem "list" i nazwą wynikowego pliku "ELF"

 

static void ledblink(void){
 800014c:    b480          push    {r7}
 800014e:    b083          sub    sp, #12
 8000150:    af00          add    r7, sp, #0
    uint32_t i;
    while(1){
        for(i=0;i<500000;i++){
 8000152:    2300          movs    r3, #0
 8000154:    607b          str    r3, [r7, #4]
 8000156:    e003          b.n    8000160 <ledblink+0x14>
            __NOP();
 8000158:    bf00          nop
        for(i=0;i<500000;i++){
 800015a:    687b          ldr    r3, [r7, #4]
 800015c:    3301          adds    r3, #1
 800015e:    607b          str    r3, [r7, #4]
 8000160:    687b          ldr    r3, [r7, #4]
 8000162:    4a05          ldr    r2, [pc, #20]    ; (8000178 <ledblink+0x2c>)
 8000164:    4293          cmp    r3, r2
 8000166:    d9f7          bls.n    8000158 <ledblink+0xc>
        }
        GPIOA->ODR ^= 0x20;
 8000168:    4b04          ldr    r3, [pc, #16]    ; (800017c <ledblink+0x30>)
 800016a:    68db          ldr    r3, [r3, #12]
 800016c:    4a03          ldr    r2, [pc, #12]    ; (800017c <ledblink+0x30>)
 800016e:    f083 0320     eor.w    r3, r3, #32
 8000172:    60d3          str    r3, [r2, #12]
        for(i=0;i<500000;i++){
 8000174:    e7ed          b.n    8000152 <ledblink+0x6>
 8000176:    bf00          nop
 8000178:    0007a11f     .word    0x0007a11f
 800017c:    40010800     .word    0x40010800

08000180 <main>:
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
 8000180:    b580          push    {r7, lr}
 8000182:    b082          sub    sp, #8
 8000184:    af00          add    r7, sp, #0

 

W oknie disassemblacji akurat nie widać wartości HEX, ale widać je w pliku list.

Przechodząc do sedna ARM ma taki urok i to chyba dobrze, że w kodzie w wygodnych dla siebie miejscach (pomiędzy procedurami, na końcach procedur) wstawia dane dla wykonującej się procedury - bo na przykład sam rozkaz:

LDR R0, = 0xABCDEF01

Nie wykona się w taki sposób jak np w C64 asm 6502

LDA #$00

Czyli załadowanie do rejestru akumulatora wartości 0, gdzie owe ZERO jest ciągiem następujących po sobie bajtów - że się tak wyrażę, tak jakby pamięć była natychmiast mixowana rozkazami i wartościami dla rejestrów. Dla 6502 ten rozkaz wygląda tak:

 

0xA9, 0x00

 

gdzie wartość 0xA9 to oznacza natychmiastowe ładowanie do akumulatora wartości, a wartość 0x00 - to właśnie ta wartość do załadowania.

W ARM to NIE ZAWSZE (szczególnie dla dużych wartości np. 0x40293617) tak nie działa - są rozkazy, gdzie udaje się załadować wartość natychmiastowo np.

MOV R0, =0x80000000

albo 

MOV R0, = 0xFFFFFFFF

 

wykonają się natychmiast i zajmą 2 bajty, bo pozwoli na to logika rdzenia razem z rejestrem przesuwającym i rozkazem inwersji bitów w przypadku 0xFFFFFFFF

No ale... Ale te nazwijmy je "TRUDNE" wartości, których nie da się załatwić shifterem czy negatorem można ładować na kilka sposobów - np po 16 bitów, albo właśnie w taki sposób, że gdzieś "W POBLIŻU" leżą te dane niezbędne do załadowania. Tak samo możesz zwrócić uwagę że nie wszystkie rozkazy są 2 bajtowe i niektóre polecenia zajmują 4 bajty, kiedy nie uda się czegoś zrobić w THUMB (style - bo i tak procesor Cortex-M jest zawsze w THUMB mode i trybu ARM nie posiada) - czyli korzysta z "dłuższych" rozkazów THUMB.

O tych danych wie debugger, dlatego ten obszar jest ignorowany i podaje tam jakieś krzaki, bo dla niego to już nie jest kod i on o tym wie.

Gwoli ścisłości należy dodać że rozkaz NOP na końcu Twojej procedury jest generowany w razie potrzeby przez kompilator, żeby było wyrównanie pomiędzy kodem i danymi do 4. Nie jestem pewien czy to jakaś zaszłość, czy konieczność, czy optymalizacja, bo wydaje mi się że to nie jest konieczne, szczególnie kiedy korzystałbyś z rozkazu LDRB - który ładuje kolejne bajty.

 

Przypuszczam że bez problemu możesz (szczególnie jeżeli masz wersję debug wynikowego elfa) spowodować disassemblację ELFA programem dumpobj z toolchaina GCC - gdzieś obok w wątku podałem przykłady korzystania z arm-none-eabi-dumpobj.exe, wówczas zobaczysz czym są te dane na końcu procedury - a jak sam zauważyłeś procedura kończy się rozkazem powrotu z podprogramu 🙂

pzdr

 

Edit: Rozkaz NOP (0xBF00) jest na końcu mojej a nie Twojej procedury , bo akurat koniec Twojej procedury (0x08001C1A BX LR czyli  0x08001C1A 0x7047) tworzy samoistne wyrównanie do 4 - następne dane są pod 0x08001C1C

 

aaaa... mnemmoniki "db" to skrót od declare bytes 🙂

 

Edytowano przez virtualny
  • Lubię! 1
Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.