Получить байтовое представление инструкции ASM в коде C - PullRequest
0 голосов
/ 19 января 2019

Есть ли способ в коде C перейти от текстового представления инструкции ASM (например, cmpwi r3, 0x20) к ее двоичному представлению (0x2c030020)?

Я пишу код, который будет встроен в другое приложение во время выполнения. Этот код должен изменить поведение / код работающей программы. Это означает, что есть такая строка кода:

*((volatile int *)(0x80001234)) = 0x2c030020;

Этот код записывает инструкцию ASM cmpwi r3, 0x20 в 0x80001234, перезаписывая текущую инструкцию по этому адресу. Теперь, имея константу «0x2c030020» в моем коде C, не зная, что это плохо, для поддержания кода. Таким образом, я обычно добавляю комментарии к коду, подобному приведенному выше, с указанием инструкции ASM: // 2c 03 00 20 = cmpwi r3, 0x20

Однако время от времени они не синхронизируются. Я мог бы быстро изменить целочисленное значение и забыть обновить комментарий, или я мог бы просто сделать опечатку в комментарии, вызывая путаницу.

Есть ли способ, как я мог бы сделать что-то подобное вместо этого? (псевдокод) *((volatile int *)(0x80001234)) = asm("cmpwi r3, 0x20"); что в результате приведет к записи 0x2c030020 в 80001234? Или мне понадобится хакерское решение с настраиваемым препроцессором, работающим над моими исходными файлами на C, заменяя инструкции ASM их байтовым кодом?

Я знаю, что есть синтаксис C для встроенного кода на ассемблере, использующего функцию asm(), но он будет выполнять данные инструкции ASM, а не давать мне их двоичное представление.

1 Ответ

0 голосов
/ 19 января 2019

Звучит как сумасшедшая вещь, но я полагаю, у вас есть на то веские причины.Жизнь без веселья без небольшого безумия.

Один из подходов, который вы можете использовать, - это использовать ассемблер во время сборки для генерации констант во время компиляции.

Первый шаг - сделатьфайл, содержащий каждую инструкцию по сборке, которую вы будете использовать, по одной на строку.

Например:

cmpwi   3,0x20
addi    3,3,0
blr

Назовите этот файл input.def.Затем используйте этот сценарий оболочки:

#!/usr/bin/env bash

(cat << HEADER
    .global main
    .text
main:
HEADER
cat input.def) > asm.s

powerpc-linux-gnu-as asm.s -o asm.o

powerpc-linux-gnu-objdump -d asm.o | \
    sed '1,/<main>/ d' | \
    paste -d'\t' - input.def | \
    awk -F'\t' '{
        bytes=$2
        asm=$4
        disasm=$3
        gsub(/ /, "", bytes);
        gsub(/[, ]+/, "_", asm);
        printf("#define ASM_%-20s 0x%s    // disassembly: %s\n", asm, bytes, disasm)
    }'

# Clean temporaries
rm asm.s asm.o

(здесь я использую GNU-ассемблер и objdump. Возможно, вам придется изменить эту часть, если вы не используете эти инструменты. Objdump используется как прославленный hexdumpутилита здесь.)

Этот сценарий оболочки:

  1. Создает файл сборки
  2. Собирает его
  3. Помещает его рядом с input.def,(Это позволяет увидеть, какую сборку вы набрали.)
  4. Переформатирует гекс, чтобы он был допустимой константой Си.Переформатирует asm, чтобы он был допустимым символом C.Затем пишет определение для сопоставления имени инструкции с константой.
  5. Поместите все это в asm.h

Это большая работа, но вы можете сделать всево время компиляции.

Создает заголовочный файл с именем asm.h:

#define ASM_cmpwi_3_0x20         0x2c030020    // disassembly: cmpwi   r3,32
#define ASM_addi_3_3_0           0x38630000    // disassembly: addi    r3,r3,0
#define ASM_blr                  0x4e800020    // disassembly: blr

Файл asm.h используется так:

#include "asm.h"
*((volatile int *)(0x80001234)) = ASM_cmpwi_3_0x20;

Есливам нужна новая константа asm, отредактируйте файл input.def и перезапустите сценарий оболочки.

...