Главная arrow Документация arrow Пойнтеры. Часть третья.
03.06.2023 г.
Краткие новости

Поздравляем всех посетителей сайта с праздником - Днём России! В этот знаменательный день мы решили порадовать всех вас новым переводом - The Hunt for Red October (N.E.S.). Эта игра сделана по одноимённому фильму, который снят по книге Тома Клэнси "Охота за Красным Октябрём". Капитан суперсовременной советской подводной лодки Марко Рамиус (!) уводит субмарину к берегам Америки, чтобы уничтожить всё восточное побережье, устроив ядерный взрыв. Снова мир находится на грани ядерной войны и его судьба зависит только от вас!

 
Цитаты
Чуковский Корней Иванович: "Перевод — это автопортрет переводчика."
Внимание! Всем-всем-всем!
Товарищи! Если у кого-то из вас вдруг завалялись ненужные (или не очень нужные) картриджи денди - не дайте пропасть добру! Приму в дар, скопирую и верну хозяину или куплю/обменяю любые интересные картриджи, особенно редкие или пиратские. С предложениями обращайтесь НА ФОРУМ или В ЛИЧКУ. Подпись: Guyver.
Пойнтеры. Часть третья. Печать E-mail
Автор Mefistotel   
30.12.2014 г.

ПОИНТЕРЫ. ЧАСТЬ ТРЕТЬЯ. (автор: Mefistotel, помощь и корректировка: Джинни, Marat)

Введение
 

В этой документации мне бы хотелось осветить некоторые приёмы по работе с указателями. Довольно часто бывают такие случаи при переводе, когда найдены 2-х байтные относительные указатели (рабочий диапазон 0xFFFF или 64 килобайта), но места в блоке под русский текст недостаточно. Более того, в пределах 64 килобайт после блока с текстом свободного места также нет в явном виде, а двухбайтные указатели дальше адресовать не могут. Чтобы качество перевода не пострадало от технических ограничений такого типа, существует чудодейственные способы выхода из ситуации. Можно попросту заменить 2-х байтные относительные указатели (рабочий диапазон 0xFFFF или 64 килобайта) на 4-х байтные абсолютные (рабочий диапазон 0xFFFFFF или 16 мегабайт). Как это сделать рассмотрим на примере следующих игр для SEGA GENESIS Toejam & Earl (J) (REV02) [!].gen и Langrisser II (J) (REV02) [T+Eng_M.I.J.E.T.].gen. Для выполнения задачи нам понадобятся шестнадцатеричный редактор (к примеру, Translhextion 1.6с Chief-NET Edition), минимальное знание ассемблера для процессора M68000 и трезвый ум. Необязательно, но для наглядности можно воспользоваться дизассемблером IDA PRO 6.1 с Sega Loader-ом.


Toejam & Earl (J) (REV02) [!].gen

В этой игре большая часть текста разбросана по рому в виде одной-двух строк, и указатели на них 2-х байтные относительные. Но на счастье переводчика при загрузке указателей на строки идёт одна лишняя инструкция (NOP). Рассмотрим подробнее, на примере строки [bogus ... game over], которая находится по адресам 0x23646-0x23659.
 
bogus
Указатель на эту строку находится по адресу 0x23574 и равен 0x00D2. Он относителен своего адреса, то есть к значению адреса прибавляем значение указателя и получаем адрес строки (0x23574 + 0x00D2 = 0x20D36). Если присмотреться, то перед и после значения указателя идут машинные коды двух инструкций: PEA (48 7A) и NOP (4E 71).
Для наглядности также можно загрузить ром в дизассемблер IDA PRO 6.1, нажать G и ввести адрес указателя 0x23572. Увидим команду загрузки указателя и текст, на который он указывает:
 
pea
 
Таким образом, процедура загрузки указателя на строку выглядит так и занимает 6 байт:
PEA #$00D2 NOP
 
Инструкция PEA записывает в стек двухбайтный адрес данных (строки в нашем случае), рассчитанный по формуле: АДРЕС ИНСТРУКЦИИ + 2 + ЗНАЧЕНИЕ (в нашем случае 0x00D2). А инструкция NOP ничего не делает и является лишней. В стек значение записывается для того, чтобы функция, которая вызывается инструкцией JSR, могла загрузить это значение из стека в регистр. А затем загрузить строку по указанному адресу [bogus ... game over].

Для изменения указателя на 4-х байтный, необходимо изменить инструкцию PEA на другую или просто заменить указатель на 4-х байтный. В роме меняем машинный код с 487A00D24E71 на 2F3C000FFE60 (инструкция Move) и получаем:


MOVE #$000FFE60, -(sp)


Эта процедура занимает также 6 байтов, то есть 2 байта 2F3C - это код инструкции Move, а 00 0F FE 60 - наш новый 4-х байтный указатель, который был выбран исходя из свободного места в роме (диапазон адресов 0xFFE60-0xFFFFF). Таким образом, были изменены инструкции на загрузку адреса строки в стек. Так как NOP была лишней, то мы вписали 4-х байтный адрес строки вместо 2-х байтного.
Теперь останется перенести строку на новый адрес в роме (0x000FFE60), не забывая поставить стопбайт /00 в конец строки. Ниже на скриншоте показано результат - длина строки была увеличена с 19 до 28 символов. Если найти адрес строки в видеопамяти, то можно ещё больше удлинить строку, а также оцентровать её.

move
 
transl
 
Стоит отметить, что данный случай со свободными байтами является скорее исключением из правил и довольно редко встречается.


Langrisser II (J) (REV02) [T+Eng_M.I.J.E.T.].gen

Рассмотрим вариант, который встречается наиболее часто в ромах. В игре также встречаются 2-х байтные относительные указатели, но лишние инструкции отсутствуют.
Для многих геймеров не секрет, что если в игровом сценарии подвести курсор к левому верхнему краю экрана в точку с координатами 2:2 и зажать кнопку В на несколько секунд, то откроется музыкальный тест. Стрелками вверх и вниз на крестовине джойстика можно выбрать и прослушать мелодии и звуки из игры.
 
 
Блок с названием композиций и звуков (далее музыкальный блок) в роме расположен по адресам 0xAE67C-0xAE99E. После него сразу же идёт массивный блок с названиями и описания предметов. Немного ниже есть даже небольшой кусок свободного места (0xAF7F0-0xAFFFF), а дальше сплошной код и данные.
Так вот, единственный относительный 2-х байтный указатель 0x5A7A на весь музыкальный блок находится по адресу 0xA8C00. Он относителен своего адреса (0xA8C00 + 0x5A7A = 0xAE67C), как и в предыдущей рассматриваемой игре. Строки в блоке отделяются стопбайтом /00 и можно спокойно менять их длину. Выделенного места не хватит под литературный перевод музыкального блока на русский язык, а имеющееся в пределах 64 килобайт свободное место уйдёт под перевод описаний и названий предметов. В такой ситуации нужно перенести музыкальный блок в другое место, изменив указатель с 2-х байтного на 4-х байтный. Рассмотрим внимательнее инструкции около нашего указателя:
 

move_b
 

Инструкция MOVE (1038) загружает байт данных (номер строки в блоке) с адреса 0xFFFFA6C8 в оперативной памяти в регистр D0, а инструкция LEA (43FA) записывает в регистр A1 двухбайтный адрес данных (строки в нашем случае), рассчитанный по формуле: АДРЕС ИНСТРУКЦИИ + 2 + ЗНАЧЕНИЕ (в нашем случае 0x5A7A). Далее инструкцией BSR вызывается функция, которая загружает это значение из стека в регистр, затем загружается строка по указанному адресу [Stop Music].
В данном случае просто заменить инструкцию LEA на MOVE с изменением понтера не выйдет, так как вся операция загрузки указателя занимает 4 байта. Необходимо переместить всю подпрограмму в другое место. Для этого с адреса 0xA8BFC прописываем переход на новый адрес, по которому имеется свободное место в роме (к примеру, в диапазоне 0x1BC612-0x1BFFFF):

JSR 001BС700 NOP

(4EB9001BС7004E71)


И куда переместили, прописываем нашу первичную подпрограмму:

MOVE.B<$A6C8>,D0 LEA #$XXXXXXXX,A1 RTS

(1038A6C843F9XXXXXXXX4E75)

где XXXXXXXX - наш новый 4-х байтный указатель на музыкальный блок,
RTS - возвращает в исходное место.
После этого не забываем перенести сам блок на новое место. Для наглядности покажем в хексредакторе, что было сделано:

 

 

В качестве эпилога

С первого взгляда всё кажется непонятным и трудным, но нужно осознать, что не обязательно сильно углубляться в дебри ассемблера, а достаточно просто посмотреть какие байты находятся около пойнтеров. С помощью IDA это будет сделать гораздо удобнее, ведь вы будете сразу видеть названия инструкций и ссылки. Затем уже можно сделать подходящую замену инструкций. Многие переводчики не озадачивают себя поиском решения, а просто сокращают свой перевод в угоду оригинальным ограничениям, тем самым снижая качество конечного продукта.

Последнее обновление ( 15.03.2016 г. )
 
« Пред.   След. »
home contact search contact search