Автор Тема: GBA прыжок и возврат  (Прочитано 690 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн consolegamer

  • Пользователь
  • Сообщений: 11
  • Torvus
    • Просмотр профиля
GBA прыжок и возврат
« : 08 Октябрь 2023, 09:51:30 »
Добрый день. Хочу модифицировать игру на гба. Но мне не понятно, как делать прыжок на адрес памяти и возврат. В денди и сега умею, там просто, а вот в гба пока что никак не получается разобраться. SDK пробовал ставить, но не могу в нём разобраться. Может кто-нибудь подскажет опкод прыжка на адрес 087FFF50 и возврата? опкод формируется непонятным образом. С помощью дизассемблера увидел код игры, и вроде бы нашёл прыжок:
   опкод           инструкция         вероятно адрес памяти, на который идёт прыжок
35 f0 ee fa          bl                                             FUN_08035864                                                                    undefined FUN_08035864()
Попробовал сам написать такую же инструкцию в гба-ассемблере goldroad и скомпилировать, но скомпилированная команда не понимается эмулятором гба, что кажется означает то, что goldroad не правильно работает
Прыжки вроде бы осуществляются командой bx


« Последнее редактирование: 08 Октябрь 2023, 10:07:08 от consolegamer »

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5086
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #1 : 08 Октябрь 2023, 12:08:15 »
У GBA процессор ARM, поэтому смотреть инструкции к нему. Инструкция b для "прыжка" без условий, относительно PC, т. е. от места вставки инструкции. bl "прыжок" на функцию и bx возврат из неё (нужен параметр, обычно lr он же r14). Абсолютные "прыжки" сложнее. Эксперименты можно делать в no$gba, ПКМ по коду > Change Instruction. Но я не разбираюсь, курите доки.

Оффлайн bugmenot

  • Пользователь
  • Сообщений: 604
  • Пол: Мужской
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #2 : 08 Октябрь 2023, 12:44:20 »

Оффлайн DrMefistO

  • Пользователь
  • Сообщений: 1294
  • Пол: Мужской
  • Sega Mega Drive reversing
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #3 : 09 Октябрь 2023, 00:09:40 »
Вот тут можно потренироваться в ассемблировании, и сразу же проверить как дизассемблируется: https://shell-storm.org/online/Online-Assembler-and-Disassembler/

Оффлайн consolegamer

  • Пользователь
  • Сообщений: 11
  • Torvus
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #4 : 11 Октябрь 2023, 09:57:43 »
Вот тут можно потренироваться в ассемблировании, и сразу же проверить как дизассемблируется: https://shell-storm.org/online/Online-Assembler-and-Disassembler/
ооочень помогает

Добавлено позже:
У GBA процессор ARM, поэтому смотреть инструкции к нему. Инструкция b для "прыжка" без условий, относительно PC, т. е. от места вставки инструкции. bl "прыжок" на функцию и bx возврат из неё (нужен параметр, обычно lr он же r14). Абсолютные "прыжки" сложнее. Эксперименты можно делать в no$gba, ПКМ по коду > Change Instruction. Но я не разбираюсь, курите доки.
как я понял, адрес, на который прыгаешь, собирается в регистре r1(например) и на него делается прыжок bx r1

Если я правильно понял, процессор гба работает с 32х битными командами только в определенном диапазоне памяти(0x03000000-...) и с 16битными командами в диапазоне 0x08000000-..., что создало проблемы при прыжке.
« Последнее редактирование: 11 Октябрь 2023, 13:04:47 от consolegamer »

Оффлайн DrMefistO

  • Пользователь
  • Сообщений: 1294
  • Пол: Мужской
  • Sega Mega Drive reversing
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #5 : 11 Октябрь 2023, 14:46:56 »
Если я правильно понял, процессор гба работает с 32х битными командами только в определенном диапазоне памяти(0x03000000-...) и с 16битными командами в диапазоне 0x08000000-..., что создало проблемы при прыжке.
Никто же не мешает в регистр поместить любое число и прыгнуть на него.

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5086
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #6 : 11 Октябрь 2023, 17:25:24 »
процессор гба работает с 32х битными командами только в определенном диапазоне памяти(0x03000000-...) и с 16битными командами в диапазоне 0x08000000-..., что создало проблемы при прыжке.
Не понял что за проблемы, диапазон 08000000- просто дольше выполняется для 32-битных инструкций из-за шины в 16 бит, поэтому там лучше выполнять THUMB инструкции (16 бит) или скопировать код во внутреннюю память (Work RAM 32K  03000000-03007FFF), как написано в CPU Mode Performance: https://problemkaputt.de/gbatek-gba-memory-map.htm.

Оффлайн consolegamer

  • Пользователь
  • Сообщений: 11
  • Torvus
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #7 : 12 Октябрь 2023, 08:51:55 »
Не понял что за проблемы, диапазон 08000000- просто дольше выполняется для 32-битных инструкций из-за шины в 16 бит, поэтому там лучше выполнять THUMB инструкции (16 бит) или скопировать код во внутреннюю память (Work RAM 32K  03000000-03007FFF), как написано в CPU Mode Performance: https://problemkaputt.de/gbatek-gba-memory-map.htm.
ну я пробовал писать 32х битные команды в диапазоне 08000000-, а cpu-трэйсер VisualBoyAdvance-SDL-H показал мне, что 32хбитные команды выполнились как 16битные, т.е .выполнились не правильно. может нужно какую-то команду давать, чтобы переключаться, я не программист))  я просто ещё не умею делать прыжки на 16 битных командах, в этом у меня проблема. а так то да, никаких проблем у специалистов.

Оффлайн consolegamer

  • Пользователь
  • Сообщений: 11
  • Torvus
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #8 : 14 Октябрь 2023, 11:05:09 »
Подскажите пож-та, если можете. Я делаю прыжок в месте, где выполняются 16битные команды, на ram-адрес 08800000, что соответствует концу рома, процессор сам при этом меняет режим и начинает исполнять команды в 32 битном режиме, далее делаю возврат, и он не переключается обратно на 16битный режим. 5 дней уже пытаюсь сделать. Вот лог процессора, в который я добавил комментарии:


Собираю адрес в регистре r1 и делаю прыжок
080754FA 2188 mov r1, #0x88             R00=00000014 R01=0000001a R02=0000000f R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=080754fc
080754FC 0509 lsl r1, r1, #0x14           R00=00000014 R01=00000088 R02=0000000f R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=080754fe
080754FE 4708 bx r1                           R00=00000014 R01=08800000 R02=0000000f R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08075500

Восстанавливаю старые команды, которые я затёр прыжком, но уже в 32битном режиме
08800000 e0900004 adds r0, r0, r4       R00=00000014 R01=08800000 R02=0000000f R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800004
08800004 e3a02000 mov r2, #0x0        R00=0807c94c R01=08800000 R02=0000000f R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800008
08800008 e19000f2 ldrsh r0, [r0, r2]      R00=0807c94c R01=08800000 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=0880000c

Собираю адрес в регистре, чтобы прыгнуть на него, т.е. вернуться обратно
0880000C e3a01008 mov r1, #0x8          R00=fffffb9b R01=08800000 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800010
08800010 e1b01601 movs r1, r1, lsl #0x0c          R00=fffffb9b R01=00000008 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800014
08800014 e2811075 add r1, r1, #0x75     R00=fffffb9b R01=00008000 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800018
08800018 e1b01201 movs r1, r1, lsl #0x04  R00=fffffb9b R01=00008075 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=0880001c
0880001C e2811005 add r1, r1, #0x5      R00=fffffb9b R01=00080750 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800020
08800020 e1b01401 movs r1, r1, lsl #0x08 R00=fffffb9b R01=00080755 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800024

Прыгаю на адрес
08800024 e12fff11 bx r1                 R00=fffffb9b R01=08075500 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08800028

И тут процессор не переключается обратно на 16битный режим, а начинает выполнять 16битные команды в 32битном режиме, и игра поэтому виснет
08075500 41081109 tstmi r8, r9, lsl #0x02   R00=fffffb9b R01=08075500 R02=00000000 R03=0807c8b4 R04=0807c938 R05=00000015 R06=fffffdac R07=00000000 R08=03000e30 R09=030005cc R10=00000100 R11=000001ff R12=00000000 R13=03007e9c R14=08074885 R15=08075504


В документации написано, что режимы меняются командой bx.

Прилагаю оригинальный ром, и ром с моими изменениями который виснет, с которого писал логи https://disk.yandex.ru/d/jb2-imm6xOzobw
« Последнее редактирование: 14 Октябрь 2023, 11:22:11 от consolegamer »

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5086
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #9 : 14 Октябрь 2023, 13:32:25 »
он не переключается обратно на 16битный режим
В 0-м бите регистра в bx должен быть 1 для переключения в Thumb, т. е. в вашем коде нужно добавить add r1,r1,1h перед bx r1. Собрать адрес 08075501 можно короче (код 32 бита):
mov r1,8000000h
add r1,r1,75000h
add r1,r1,500h
add r1,r1,1h
bx r1
Ещё короче, как генерируется инструкция ldr r0,=0x08075501, в данном случае:
ldr r1, [pc, #0] ; Адрес лежит через 4 байта + 0 байт (#0)
bx r1
01 55 07 08 ; Байты сразу после bx r1
Байты инструкций тогда E59F1000 E12FFF11 08075501.
UPD: Вместо ADD можно использовать ORR, не знаю будет ли разница, в описании к ассемблеру FASMARM увидел макрос как раз для сборки адреса https://gbadev.org/tools.php?showinfo=1399:
macro imm32 reg,immediate {
mov reg,immediate and $FF
orr reg,immediate and $FF00
orr reg,immediate and $FF0000
orr reg,immediate and $FF000000
}
Use imm32 Rd,$12345678 in your code etc...
Только нужно помнить, что макрос всегда занимает 4 инструкции, а собрать можно короче, т. к. одна инструкция включает 8 бит значения и 4 бита сдвига, поэтому для уменьшения кода ассемблер должен сам генерировать код.
« Последнее редактирование: 14 Октябрь 2023, 15:28:09 от Sharpnull »

Оффлайн consolegamer

  • Пользователь
  • Сообщений: 11
  • Torvus
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #10 : 14 Октябрь 2023, 17:27:07 »
С add r1,r1,1h завелась игра . Вы - мои герои

Оффлайн DrMefistO

  • Пользователь
  • Сообщений: 1294
  • Пол: Мужской
  • Sega Mega Drive reversing
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #11 : 14 Октябрь 2023, 20:22:26 »
А Армов есть возможность добавлять сразу со сдвигом:
ADD r0, r1, r2, LSL #4
Типа того, так будет короче.

Оффлайн Sharpnull

  • Пользователь
  • Сообщений: 5086
    • Просмотр профиля
GBA прыжок и возврат
« Ответ #12 : 14 Октябрь 2023, 20:58:54 »
Типа того, так будет короче.
Короче, чем что? Для r1=08075501 это не будет короче, чем (или orr):
mov r1,8000000h
add r1,r1,75000h
add r1,r1,500h
add r1,r1,1h
Если только в других регистрах что-то есть или хитрости с другими инструкциями. Тем более не короче ldr.