2012-02-20 13 views
13

Próbuję uczyć się umiejętności przydatnych w modulacji oprogramowania (dla których nie mam kodu źródłowego) Te pytania dotyczą używania BX z kciuka do skakania lub wywoływania innego istniejącego kodu kciuka.Ramię/Thumb: używanie BX w kodzie Thumb, wywoływanie funkcji Thumb lub przechodzenie do instrukcji Thumb w innej funkcji

  1. Jak używać BX do JUMP do istniejącego kodu THUMB oprogramowania układowego, z mojego kodu THUMB.
  2. Jak używać BX do wywoływania istniejącej funkcji THUMB (najpierw trzeba ustawić LR), z mojego kodu THUMB.

Rozumiem, że cpu patrzy na lsb bit (bit 0) i muszę upewnić się, że jest ustawiony na 1 w celu utrzymania stanu CPU „stan kciuk”. więc myślę, że trzeba dodać 1, aby ustawić bit LSB do 1.

... więc powiedzieć, chcę po prostu skoczyć do 0x24000 (w środku jakiegoś istniejącego kodu kciuka)

LDR R6, =0x24000 
ADD R6, #1  @ (set lsb to 1) 
BX R6 

Myślę, że to prawda?

Teraz mów, że chcę zadzwonić do istniejącej funkcji kciuka, używając BX, i chcę, żeby ona wróciła do mnie, więc muszę ustawić LR tam, gdzie chcę, aby powrócił.

Powiedzmy funkcja chcę zadzwonić to na 0x24000 Było suggested to me używać:

ldr r2, =0x24000 
mov lr, pc 
bx r2 

Nadchodzi czego nie rozumiem:

  1. adres w R2 robi nie ma ustawionego bitu lsb ... więc czy bx r2 nie przełączy się na tryb ARM?

  2. The LR .. Komputer ma adres (początek aktualnej instrukcji, + 4), jak mi powiedziano. W kciuku i ramieniu każdy adres instrukcji musi być wyrównany (16-bitowy lub 32-bitowy), więc nie będzie miał bitu LSB ustawionego na 1. Tylko liczby nieparzyste mają ustawiony bit lsb na 1.

Tak więc w powyższym kodzie ustawiam LR na (PC), adres, który NIE ma również ustawionego 1 bit lsb. Więc gdy funkcja, którą wywołałem, przychodzi do epilogu, i robi BX LR, ... uhmmm ... jak to działa, aby powrócić do mojego kodu THUMB? Muszę czegoś pomijać ...

Zwykle do wywoływania funkcji używana jest funkcja BL. Instrukcja mówi, że instrukcja BL ustawia LR na następną linię kodu ... Czy to oznacza, że ​​(zwykle używana) instrukcja THUMB ustawia LR na return addr + 1?

Odpowiedz

19

Wow, dziękuję za zaproszenie mnie do tego. Wiem, że wypróbowałem kod qemu w http://github.com/dwelch67/yagbat i pomyślałem XPUT32, który nazywa PUT32 w sposób, w jaki opisujesz, i zadziałało. Ale wydaje się, że nie działa. Stworzyłem wiele eksperymentów i jestem zaskoczony, nie tego oczekiwałem. Teraz widzę, dlaczego linker gnu robi to, co robi. Przepraszam, że to długa odpowiedź, ale uważam, że jest bardzo cenna. Jest to mylący temat, wiem, że źle się przez lata myślałem, że PC przeciąga tryb nieco, ale to nie robi.

Zanim zacznę z poniższych eksperymentach, jeśli masz zamiar to zrobić:

LDR R6, =0x24000 
ADD R6, #1  @ (set lsb to 1) 
BX R6 

bo pan wie, że 0x24000 jest kod kciuk, po prostu to zrobić w zamian:

LDR R6, =0x24001 
BX R6 

I tak, w ten sposób rozgałęziacie się na kciuk z ramienia lub kciuka, jeśli zdajecie sobie sprawę, że ten adres 0x24000 na sztywno jest instrukcją kciuka, którą rejestrujecie razem z rejestrem zawierającym adres plus jeden.

jeśli nie znasz adresu, ale znasz nazwę adres

ldr r6,=something 
bx r6 

Zaletą jest to, że coś może być ramię lub kciuk adres i powyższy kod po prostu działa. Dobrze to działa, jeśli łącznik właściwie nie wie, jaki rodzaj etykiety, która jest ramię lub kciuk, jeśli zostanie pomieszane to przyzwyczajenie praca prawo jak widać tutaj

.thumb 
ping: 
    ldr r0,=pong 
    bx r0 
.code 32 
pong: 
    ldr r0,=ping 
    bx r0 


d6008148 <ping>: 
d6008148: 4803  ldr r0, [pc, #12] ; (d6008158 <pong+0xc>) 
d600814a: 4700  bx r0 

d600814c <pong>: 
d600814c: e59f0008 ldr r0, [pc, #8] ; d600815c <pong+0x10> 
d6008150: e12fff10 bx r0 

d6008158: d600814c strle r8, [r0], -ip, asr #2 
d600815c: d6008148 strle r8, [r0], -r8, asr #2 

że nie działał pong chciał wyciągnąć adres kciuka z 0xD600815C, ale dostałem adres ramienia.

to wszystko rzeczy gnu assembler btw, dla innych narzędzi może być konieczne zrobienie czegoś innego. W przypadku gazu należy umieścić .thumb_func przed etykietą, która ma być zadeklarowana jako etykieta kciuka (termin func implying function jest mylący, nie martw się o to, co .thumb_func oznacza, że ​​jest to tylko gra asembler/linker).

.thumb 
.thumb_func 
ping: 
    ldr r0,=pong 
    bx r0 
.code 32 
pong: 
    ldr r0,=ping 
    bx r0 

i teraz mamy co chcieliśmy

d6008148 <ping>: 
d6008148: 4803  ldr r0, [pc, #12] ; (d6008158 <pong+0xc>) 
d600814a: 4700  bx r0 

d600814c <pong>: 
d600814c: e59f0008 ldr r0, [pc, #8] ; d600815c <pong+0x10> 
d6008150: e12fff10 bx r0 

d6008158: d600814c strle r8, [r0], -ip, asr #2 
d600815c: d6008149 strle r8, [r0], -r9, asr #2 

0xD600815C że lsbit jest tak ustawiona, że ​​nie trzeba wykonywać żadnej pracy. Kompilator zajmuje się tym wszystkim, gdy na przykład wykonujesz wywołania funkcji C. Dla asemblera musisz jednak użyć tej .thumb_func (lub innej dyrektywy, jeśli istnieje), aby uzyskać informację o tym, że jest to etykieta kciuka i ustawić dla ciebie lsbit.

Tak więc poniższy eksperyment został wykonany na mpcore, który jest ARM11, ale próbowałem również funkcji testthumb od 1 do 4 na ARM7TDMI i qemu z tymi samymi wynikami.

.globl testarm 
testarm: 
    mov r0,pc 
    bx lr 

armbounce: 
    mov r0,lr 
    bx lr 

.thumb 
.thumb_func 
.globl testthumb1 
testthumb1: 
    mov r0,pc 
    bx lr 
    nop 
    nop 
    nop 
bounce: 
    bx lr 
.thumb_func 
.globl testthumb2 
testthumb2: 
    mov r2,lr 
    mov r0,pc 
    bl bounce 
    bx r2 
    nop 
    nop 
    nop 
.thumb_func 
.globl testthumb3 
testthumb3: 
    mov r2,lr 
    mov lr,pc 
    mov r0,lr 
    bx r2 
    nop 
    nop 
    nop 
.thumb_func 
.globl testthumb4 
testthumb4: 
    push {lr} 
    ldr r2,=armbounce 
    mov r1,pc ;@ -4 
    add r1,#5 ;@ -2 
    mov lr,r1 ;@ +0 
    bx r2  ;@ +2 
    pop {r2} ;@ +4 
    bx r2 
.thumb_func 
.globl testthumb5 
testthumb5: 
    push {lr} 
    ldr r2,=armbounce 
    mov lr,pc 
    bx r2 
    pop {r2} 
    bx r2 
.thumb_func 
.globl testthumb6 
testthumb6: 
    push {lr} 
    bl testthumb6a 
.thumb_func 
testthumb6a: 
    mov r0,lr 
    pop {r2} 
    bx r2 

.thumb_func 
.globl testthumb7 
testthumb7: 
    push {lr} 
    bl armbounce_thumb 
    pop {r2} 
    bx r2 

.thumb_func 
.globl testthumb8 
testthumb8: 
    push {lr} 
    bl armbounce_thumb_two 
    pop {r2} 
    bx r2 

.align 4 
armbounce_thumb: 
    ldr r1,[pc] 
    bx r1 
.word armbounce 

nop 
.align 4 
armbounce_thumb_two: 
    bx pc 
    nop 
.code 32 
    b armbounce 

która staje

d60080b4 <testarm>: 
d60080b4: e1a0000f mov r0, pc 
d60080b8: e12fff1e bx lr 

d60080bc <armbounce>: 
d60080bc: e1a0000e mov r0, lr 
d60080c0: e12fff1e bx lr 

d60080c4 <testthumb1>: 
d60080c4: 4678  mov r0, pc 
d60080c6: 4770  bx lr 
d60080c8: 46c0  nop   ; (mov r8, r8) 
d60080ca: 46c0  nop   ; (mov r8, r8) 
d60080cc: 46c0  nop   ; (mov r8, r8) 

d60080ce <bounce>: 
d60080ce: 4770  bx lr 

d60080d0 <testthumb2>: 
d60080d0: 4672  mov r2, lr 
d60080d2: 4678  mov r0, pc 
d60080d4: f7ff fffb bl d60080ce <bounce> 
d60080d8: 4710  bx r2 
d60080da: 46c0  nop   ; (mov r8, r8) 
d60080dc: 46c0  nop   ; (mov r8, r8) 
d60080de: 46c0  nop   ; (mov r8, r8) 

d60080e0 <testthumb3>: 
d60080e0: 4672  mov r2, lr 
d60080e2: 46fe  mov lr, pc 
d60080e4: 4670  mov r0, lr 
d60080e6: 4710  bx r2 
d60080e8: 46c0  nop   ; (mov r8, r8) 
d60080ea: 46c0  nop   ; (mov r8, r8) 
d60080ec: 46c0  nop   ; (mov r8, r8) 

d60080ee <testthumb4>: 
d60080ee: b500  push {lr} 
d60080f0: 4a15  ldr r2, [pc, #84] ; (d6008148 <armbounce_thumb_two+0x8>) 
d60080f2: 4679  mov r1, pc 
d60080f4: 3105  adds r1, #5 
d60080f6: 468e  mov lr, r1 
d60080f8: 4710  bx r2 
d60080fa: bc04  pop {r2} 
d60080fc: 4710  bx r2 

d60080fe <testthumb5>: 
d60080fe: b500  push {lr} 
d6008100: 4a11  ldr r2, [pc, #68] ; (d6008148 <armbounce_thumb_two+0x8>) 
d6008102: 46fe  mov lr, pc 
d6008104: 4710  bx r2 
d6008106: bc04  pop {r2} 
d6008108: 4710  bx r2 

d600810a <testthumb6>: 
d600810a: b500  push {lr} 
d600810c: f000 f800 bl d6008110 <testthumb6a> 

d6008110 <testthumb6a>: 
d6008110: 4670  mov r0, lr 
d6008112: bc04  pop {r2} 
d6008114: 4710  bx r2 

d6008116 <testthumb7>: 
d6008116: b500  push {lr} 
d6008118: f000 f80a bl d6008130 <armbounce_thumb> 
d600811c: bc04  pop {r2} 
d600811e: 4710  bx r2 

d6008120 <testthumb8>: 
d6008120: b500  push {lr} 
d6008122: f000 f80d bl d6008140 <armbounce_thumb_two> 
d6008126: bc04  pop {r2} 
d6008128: 4710  bx r2 
d600812a: 46c0  nop   ; (mov r8, r8) 
d600812c: 46c0  nop   ; (mov r8, r8) 
d600812e: 46c0  nop   ; (mov r8, r8) 

d6008130 <armbounce_thumb>: 
d6008130: 4900  ldr r1, [pc, #0] ; (d6008134 <armbounce_thumb+0x4>) 
d6008132: 4708  bx r1 
d6008134: d60080bc   ; <UNDEFINED> instruction: 0xd60080bc 
d6008138: 46c0  nop   ; (mov r8, r8) 
d600813a: 46c0  nop   ; (mov r8, r8) 
d600813c: 46c0  nop   ; (mov r8, r8) 
d600813e: 46c0  nop   ; (mov r8, r8) 

d6008140 <armbounce_thumb_two>: 
d6008140: 4778  bx pc 
d6008142: 46c0  nop   ; (mov r8, r8) 
d6008144: eaffffdc b d60080bc <armbounce> 
d6008148: d60080bc   ; <UNDEFINED> instruction: 0xd60080bc 
d600814c: e1a00000 nop   ; (mov r0, r0) 

a wyniki wywoływania i drukowania wszystkich tych funkcji

D60080BC testarm 
D60080C8 testthumb1 
D60080D6 testthumb2 
D60080E6 testthumb3 
D60080FB testthumb4 
     testthumb5 crashes 
D6008111 testthumb6 
D600811D testthumb7 
D6008127 testthumb8 

Więc co to wszystko robi i co to ma zrobić ze swoim pytanie. Ma to związek z trybem mieszanym z trybu kciuka (a także z ramienia, które jest prostsze)

Programowałem ARM i tryb kciuka na tym poziomie przez wiele lat, i jakoś przez cały czas było źle. Myślałem, że licznik programu zawsze utrzymywał tryb na tym lsbicie, wiem, że wiesz, że chcesz go ustawić lub nie ustawić, gdy wykonujesz instrukcję bx.

Bardzo wcześnie w opisie CPU procesora ARM w podręczniku ARM Architectural Reference Manual (jeśli piszesz asembler, powinieneś już to mieć, jeśli nie, większość pytań będzie odpowiedziana).

Program counter Register 15 is the Program Counter (PC). It can be used in most 
     instructions as a pointer to the instruction which is two instructions after 
     the instruction being executed... 

Więc pozwala sprawdzić i zobaczyć, co to naprawdę znaczy, to znaczy w trybie ramienia dwie instrukcje, 8 bajtów do przodu? i w trybie kciuka, dwie instrukcje do przodu lub 4 bajty do przodu?

Zatem testarm weryfikuje, czy licznik programu ma 8 bajtów do przodu. która jest również dwiema instrukcjami.

testthumb1 sprawdza, czy program ma 4 bajty do przodu, co w tym przypadku jest również dwiema instrukcjami.

testthumb2

d60080d2: 4678  mov r0, pc 
d60080d4: f7ff fffb bl d60080ce <bounce> 
d60080d8: 4710  bx r2 

jeśli licznik program był dwa „instrukcje” głowa chcielibyśmy dostać 0xD60080D8 ale zamiast dostać 0xD60080D6 który jest cztery bajty do przodu, a to sprawia, że ​​o wiele więcej sensu. Tryb uzbrojenia 8 bajtów do przodu, tryb kciuka 4 bajty do przodu, brak zakłóceń z instrukcjami dekodowania (lub danych), które wyprzedzają wykonywanego kodu, po prostu dodaj 4 lub 8.

testthumb3 była nadzieją, że mov lr, pc był specjalne, nie jest.

jeśli nie widzisz jeszcze wzorca, lsbita licznika programu NIE jest ustawiona i myślę, że ma to sens na przykład w tablicach rozgałęzień. Więc mov lr, PC w trybie kciuka NIE ustawia rejestru linków w prawo do zwrotu.

testthumb4 w bardzo bolesny sposób bierze licznik programu, gdziekolwiek ten kod dzieje skończyć i na podstawie starannie umieszczone instrukcje, oblicza adres zwrotny, jeśli zmienisz tę sekwencję instrukcji pomiędzy mov r1, PC i bx r2 ty trzeba ponownie dostroić dodawanie. Teraz, dlaczego nie mógł po prostu zrobić coś takiego:

add r1,pc,#1 
bx r2 

z instrukcjami kciuka cant z thumb2 prawdopodobnie mógł. I wydaje się, że jest kilka procesorów (armv7), które obsługują instrukcje ramion i kciuka/kciuka2, więc możesz znaleźć się w sytuacji, w której chciałbyś to zrobić, ale nie dodałeśby # 1, ponieważ instrukcja dodawania kciuka2, jeśli jest taka która pozwala na wyższe rejestry i ma trzy operandy to 4 bajty kciuka 2. (musisz dodać # 3).

Więc testthumb5 jest bezpośrednio z kodu, który pokazałem ci, który prowadzi do części tego pytania, i ulega awarii. to nie tak działa, przepraszam, że wprowadzam w błąd ludzi, spróbuję wrócić i załatwić pytania SO, z których korzystałem.

testthumb6 to eksperyment, dzięki któremu wszyscy nie jesteśmy szaleni. Wszystko dobrze, że rejestr linków rzeczywiście jest ustawiony na wartość lsbita, dzięki czemu po bx lr później poznaje tryb z tego bitu.

testthumb7, pochodzi od trampoliny po stronie ARM, którą widzisz, gdy linker robi przechodząc z trybu uzbrojenia do trybu kciuka, w tym przypadku przechodzę z trybu kciuka do trybu uzbrojenia. dlaczego nie może tego zrobić linker? ponieważ w trybie kciuka przynajmniej musisz użyć niskiego rejestru iw tym momencie gry, po skompilowaniu kodu linker nie ma możliwości dowiedzenia się, jaki rejestr może on wyrzucić. W trybie uzbrojenia rejestr IP, nie wiem, co to może być r12, może zostać zniszczony, domyślam się, że jest zarezerwowany do użycia przez kompilator. Wiem, że w tym przypadku r1 może zostać zniszczony i wykorzystany, a to działa zgodnie z oczekiwaniami. zostanie wywołany kod armbounce, który pobiera rejestr linków, jeśli chcesz wrócić do niego, który jest instrukcją kciuka (zestaw lsbita) po błędzie armbounce_thumb w funkcji testthumb7, dokładnie tam, gdzie chcemy, żeby była.

testthumb8 tak działa linker gnu, gdy musi przejść z trybu kciuka do trybu uzbrojenia. instrukcja bl jest ustawiona, aby przejść do trampoliny.następnie robią coś bardzo podstępnego i szalenie wyglądającego.

d6008140 <armbounce_thumb_two>: 
d6008140: 4778  bx pc 
d6008142: 46c0  nop   ; (mov r8, r8) 
d6008144: eaffffdc b d60080bc <armbounce> 

A bx pc. Wiemy z powyższych eksperymentów, że komputer ma cztery bajty wcześniej, wiemy również, że lsbit NIE jest ustawiony. Więc to, co to mówi, jest odgałęzieniem do KODU ARM, który wynosi cztery bajty po tym. Nop jest dwubajtowym elementem dystansowym, a następnie musimy wygenerować instrukcję ARM cztery bajty przed nami I ZOSTAĆ WYBRANE NA CZTERECH DRUGIEGO BYTU GRANICY, a my zrobimy to bezwarunkową gałęzią do dowolnego miejsca, do którego zmierzamy, może to być coś ab lub ldr pc , = coś zależnie od tego, jak daleko musisz się posunąć. Bardzo trudne.

Oryginalny bl arm_bounce_thumb_two ustawia rejestr linków, aby powrócić do instrukcji po tym bł. Trampolina nie modyfikuje rejestru linków, po prostu wykonuje gałęzie.

jeśli chcesz dostać się do trybu kciuka z ramienia wtedy zrobić co łącznik robi:

... 
bl myfun_from_arm 
... 


myfun_from_arm: 
    ldr ip,[pc] 
    bx ip 
.word myfun 

który wygląda tak, gdy robią to (pobrana z innego binarnego nie na 0xD6008xxx ale 0x0001xxxx).

101f8: eb00003a bl 102e8 <__testthumb1_from_arm> 


000102e8 <__testthumb1_from_arm>: 
    102e8: e59fc000 ldr ip, [pc] ; 102f0 <__testthumb1_from_arm+0x8> 
    102ec: e12fff1c bx ip 
    102f0: 00010147 andeq r0, r1, r7, asr #2 

więc cokolwiek to jest rejestr ip (r12?), Że nie przeszkadza zaśmiecać go i zakładam, zapraszamy do jej kosza siebie.

+0

absolutnie kocham twoją odpowiedź i trud. Jest to również to, co zauważyłem w tym rozwiązanym firmware, nad którym pracuję. I wyjaśnia awarie w moich testach (nie korzystałem z emulatora .. po prostu w górę modded firmware i ładowałem układ flash..lol) Firmware ma kod trybu ARM, w dolnej części, i kod PIN tylko dla głównej części aplikacji . Ale tak, tak właśnie działa Thumb to Arm i Arm to Thumb. To oprogramowanie zostało skompilowane z ADS v 1.2 btw. – vmanta

+0

Też dodam, o ile mogę powiedzieć i o ile czytałem, w trybie kciuka (kciuka 1 .. jeśli tam jest coś takiego) możesz wyrzucić śmieci R0 - R3, ale musisz Push/Pop R4 - R7 . Firmware, na który patrzę, robi to, a także zauważyłem, że robi to również kod z gnu gcc (arm-elf-gcc). Cóż ... to świetnie, że wykonałeś wszystkie te testy, ponieważ robię to samo na urządzeniu w moich modach oprogramowania, ale czasami czasami się tak mylę (szczególnie, gdy zdarzają się awarie z powodu innych błędów), których używam do korzystania z BL (ból w tyłku ... z wyliczaniem przesunięć, jak to wyjaśniłem) – vmanta

+0

Mam zamiar napisać program, który będzie użyty jako preprocesor do "jak" i ustawić dla mnie moje przesunięcia ... może użyć specjalnej notacji. .. jak BL ADR: 0x24000, i mój program do obliczenia tego przesunięcia dla mnie ... ahhh ... byłoby cudownie .. dlaczego nikt nie pomyślał o tym lol ... może jest jednak sposób, po prostu nie jeszcze to wiem ... i jeśli istnieje sposób, jak sądzę, byłby to jakiś rodzaj dyrektywy w linkerze. Nie wiem, ale czytam i czytam ... spędziłem za dużo czasu. Hej, dziękuję bardzo ... i cieszę się, że znalazłeś PRAWDĘ .. hehe – vmanta

Powiązane problemy