Перевод с C на ARM Assembly - постоянно возникают ошибки сегментации, путаница с ldr и str? - PullRequest
0 голосов
/ 17 ноября 2018

Я новичок в сборке ARM и пытаюсь перевести несколько простых фрагментов кода из C в сборку.Я не уверен, правильно ли я использую ldr и str (хотя я чувствую, что я все перепробовал), и я продолжаю получать ошибку сегмента, когда пытаюсь его запустить.

Код C

int main() {
    int x = 10;
    int y = 5;
    int z = 20;

    int min = y;

    if (x < min) {min = x;}
    if (z < min) {min = z;}

    return min;
}

Мой код сборки:

.global main
.text

main:
    push {ip, lr}

    mov r0, #10
    mov r1, #5
    mov r2, #20

    str r3, [r1]

    cmp r0, r3
    bge done
    str r0, [r3]

    cmp r2, r3
    bge done
    str r2, [r3]

done:
    ldr r0, [r3]
    pop {ip, pc}

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

TonyK's answer достаточно хорошо раскрывает источник ваших ошибок. Меня поражает, что вам может быть полезно увидеть, как компилятор справится с компиляцией простой программы, подобной этой; видя, как компилятор выделяет место в стеке для этих переменных, и видя, как он правильно использует LDR и STR, можно легко научиться.

Если вы используете gcc, попробуйте добавить -S -O1 к параметрам компилятора, чтобы включить мягкую оптимизацию (-O1) и запросить язык ассемблера в качестве выходного (-S). Вывод будет чередовать исходный код C в сгенерированный язык ассемблера, что, надеюсь, облегчит его понимание.

0 голосов
/ 17 ноября 2018

Код C:

int main() {
    int x = 10;
    int y = 5;
    int z = 20;

    int min = y;

    if (x < min) {min = x;}
    if (z < min) {min = z;}

    return min;
}

Не используйте ldr и str, поскольку они сохраняют значение регистров в памяти.Например, str rX, [rY] означает использование значения «rY» в качестве адреса памяти для хранения значения «rX».Нет необходимости использовать память, когда у вас есть много доступных регистров.Например,

mov   r0, #5    ; min = y = #5
mov   r1, #10   ; x = 10
mov   r2, #20   ; z = 20
cmp   r1, r0    ; if (x < min)
movlt r0, r1    ;  min = x
cmp   r2, r0    ; if (z < min)
movlt r0, r2    ;  min = z
mov   pc, lr    ; return min (is r0)

близко, если не завершено.Пожалуйста, просмотрите мой регистр использования, как некоторые могут быть транспонированы.Также вы можете подумать, нужно ли вам подписывать или подписывать.Ваш оригинал использовал bge done, который не будет работать, если 'x> y> z'.Вы должны использовать «меньше чем» в соответствии с кодом «C».

Я бы предложил не использовать компилятор , чтобы начать с для очень простого кода, подобного этому.Если у вас много переменных, начните с компилятора.После того, как вы попытаетесь что-то сделать, посмотрите, что делает компилятор.В некоторых случаях у вас может быть лучшая структурная идея, чем у компилятора;вероятно, не для численной проблемы, как это.Если вы сразу перейдете к компилятору, вам будет сложнее подумать об альтернативных атаках на кодирование функции.Часто идеи как из вашей первоначальной попытки, так и из компилятора объединяются для чего-то довольно приятного.

0 голосов
/ 17 ноября 2018

ОК, для каждой из ваших переменных вы должны решить, где вы будете хранить ее:

  • вы можете сохранить его в регистре, что нормально, если у вас достаточно запасных регистров;
  • вы можете хранить его по фиксированному адресу, который подходит для глобальных и статических переменных, но не подходит для локальных переменных;
  • вы можете сохранить его в стеке, где обычно хранятся локальные переменные, если не хватает регистров для обхода. Это больше работы, так как вы должны загружать и хранить его каждый раз, когда захотите получить к нему доступ.

Твоя функция сводить их на нет. Вы сохраняете x,y,z в регистрах r0,r1,r2, но затем обрабатываете y, как если бы оно хранилось по адресу 5, тогда как на самом деле оно хранится в регистре r1. Вы не хотите использовать здесь инструкцию доступа к памяти str r3, [r1], потому что в памяти ничего нет; достаточно mov r3,r1.

Остальная часть кода также не работает, но я не буду вдаваться в подробности. Ваша функция достаточно проста, чтобы у вас было более чем достаточно регистров, поэтому я предлагаю вам переписать ее, чтобы использовать регистры для всех переменных. Нет ldr/str инструкций вообще, просто mov инструкций.

И посмотрите на ассемблерный код, сгенерированный вашим компилятором C, чтобы почувствовать более сложные ситуации, когда некоторые или все переменные должны храниться в стеке.

Удачи!

...