Вызов внешней программы, загруженной во время выполнения и получение возвращаемых данных на голом железе - PullRequest
3 голосов
/ 03 октября 2019

У меня есть система с процессором MPC8548. Моя работа заключается в том, чтобы отправить вторую (внешнюю) программу на работающую прошивку и выполнить ее.

У меня настроен кросс-компилятор для сборки базовой прошивки и внешнего кода.

Мне удалось отправить отдельную программу во время выполнения (я не уверен, что это правильно, ноКажется, это работает). Вот как я это сделал: в оригинальной прошивке я освободил место для внешнего кода, вставив множество nop инструкций, начиная с определенного адреса памяти в разделе .text. После этого во время выполнения я скопировал полученный внешний код (скомпилированный код с использованием gcc, файл .o) по этому адресу памяти, используя memcpy. Затем в оригинальной прошивке я сделал указатель на функцию, указывая на эту ячейку памяти и вызвал ее.

Это внешний простой код:

int external_main(void)
{
    int x = 11;
    return x;
}

И вот как я его назвалв исходной прошивке:

int (*extFuncPtr)(void);
extFuncPtr = &external_start;
int x = extFuncPtr();

external_start указано в разделе .text скрипта компоновщика (это начальный адрес инструкции nop) и в коде, объявленном как extern unsigned char external_start;Я распечатал эту область памяти и внешний код там, и он успешно работает (если я загружаю туда какой-то мусор, он вылетает).

Моя проблема в том, что я не могу получить какие-либо возвращаемые данные из внешнегокод. Значение x будет мусором. Я попытался передать int* в качестве параметра функции, но он все еще пуст. Я также пытался что-то написать по фиксированному адресу (во внешнем коде) и прочитать тот же адрес в прошивке, но это тоже не сработало.

У меня вопрос, возможно ли получить какие-либо данные? из внешнего кода? Возможно, я что-то делаю не так или что-то упущено.

Есть ли другие способы решения этой проблемы?

EDIT 1 Это сгенерированная сборка внешнего кода(вызывая objdump):

00000000 <external_main>:
0:  94 21 ff e0     stwu    r1,-32(r1)
4:  93 e1 00 1c     stw     r31,28(r1)
8:  7c 3f 0b 78     mr      r31,r1
c:  39 20 00 0b     li      r9,11
10: 91 3f 00 08     stw     r9,8(r31)
14: 81 3f 00 08     lwz     r9,8(r31)
18: 7d 23 4b 78     mr      r3,r9
1c: 39 7f 00 20     addi    r11,r31,32
20: 83 eb ff fc     lwz     r31,-4(r11)
24: 7d 61 5b 78     mr      r1,r11
28: 4e 80 00 20     blr

Если я добавлю эту функцию external_main в прошивку, она выдаст те же инструкции. И когда я его вызываю, это выглядит так:

   6dbdc:   4b ff 74 b5     bl      65090 <external_main>
   6dbe0:   90 7f 00 3c     stw     r3,60(r31)

И это сгенерированные инструкции части указателя функции:

   6dbb8:   3d 20 00 15     lis     r9,21
   6dbbc:   39 29 18 ec     addi    r9,r9,6380
   6dbc0:   91 3f 00 34     stw     r9,52(r31)
   6dbc4:   81 3f 00 34     lwz     r9,52(r31)
   6dbc8:   7d 29 03 a6     mtctr   r9
   6dbcc:   4e 80 04 21     bctrl
   6dbd0:   90 7f 00 38     stw     r3,56(r31)

EDIT 2

Итак, я много чего пробовал, чтобы увидеть, в чем может быть проблема, включая загрузку всей основной прошивки в качестве внешней программы (она также вводит прошивку в прошивку во время выполнения). Я вызвал функцию, которая возвращает число, и это сработало. Поэтому я начал очищать вторичную прошивку (выбрасывая все ненужное), постоянно проверяя, работает ли она по-прежнему или нет. И он работал до тех пор, пока размер двоичного файла не стал меньше 16 килобайт.

Когда размер внешней программы меньше 16 КБ, он просто не работает (не может получить никаких возвращаемых значений), но когда он равен 16или выше, это работает. Он возвращает значения, также если я передам указатель на массив в качестве входного параметра (выделенный в базовой прошивке) и заполню его во внешнем коде, когда он вернет, массив будет там, заполнен.

Дон 'Я не знаю, почему это происходит, но это работает. Внешний код в любом случае не будет меньше 16 КБ, так что это победа в моей книге. Если у кого-то есть идея, почему он так себя ведет, я буду рад это услышать.

...