2016-10-31 2 views
0

Я новичок. У меня возникают трудности с пониманием карты памяти памяти ARM.Сортировка ARM Assembly

Я нашел пример алгоритма простой сортировки

AREA ARM, CODE, READONLY 

    CODE32 
    PRESERVE8 

    EXPORT __sortc 
    ; r0 = &arr[0] 
    ; r1 = length 

__sortc 
    stmfd sp!, {r2-r9, lr} 

    mov r4, r1     ; inner loop counter 
    mov r3, r4 
    sub r1, r1, #1 
    mov r9, r1     ; outer loop counter       

outer_loop 
    mov r5, r0 
    mov r4, r3 

inner_loop 
    ldr r6, [r5], #4 
    ldr r7, [r5] 
    cmp r7, r6 

    ; swap without swp 
    strls r6, [r5] 
    strls r7, [r5, #-4] 

    subs r4, r4, #1 
    bne inner_loop 

    subs r9, r9, #1 
    bne outer_loop 

    ldmfd sp!, {r2-r9, pc}^ 

    END 

И эта сборка должна вызываться таким образом из кода C

#define MAX_ELEMENTS 10 

extern void __sortc(int *, int); 

int main() 
{ 
     int arr[MAX_ELEMENTS] = {5, 4, 1, 3, 2, 12, 55, 64, 77, 10}; 

    __sortc(arr, MAX_ELEMENTS); 

    return 0; 
} 

Насколько я понимаю, этот код создает массив целых чисел на стек и вызовы _sortc функция, реализованная в сборке. Эта функция принимает эти значения из стека и сортирует их и возвращает обратно в стек. Я прав ?

Интересно, как я могу реализовать этот пример, используя только сборку.

Например, определяющего массив целых чисел

DCD 3, 7, 2, 8, 5, 7, 2, 6

КСТАТИ Где ДКД объявленные переменные хранятся в памяти ??

Как я могу работать со значениями, объявленными таким образом? Пожалуйста, объясните, как я могу реализовать это с помощью сборки только без кода C, даже без стека, только с необработанными данными.

Я пишу для ARM7TDMI архитектуры

ответ

0

AREA ARM, CODE, READONLY - это метки начала раздела для кода в источнике.

С аналогичной AREA myData, DATA, READWRITE вы можете начать раздел, где можно определить данные, как data1 DCD 1,2,3, это будет компилировать как три слова со значениями 1, 2, 3 в последовательных байтов, с ярлыком data1, указывающий на первый байт первого слова. (некоторые из AREA документов из Google).

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

Также ссылки на сценарий компоновщика и ассемблера могут влиять на размер доступного стека и где он отображается в физической памяти.

Итак, для вашей конкретной платформы: google для сопоставлений памяти в Интернете и проверки скрипта компоновщика (для начала просто используйте параметр компоновщика для создания файла .map, чтобы увидеть, где код и данные нацелены на приземление).

Таким образом, вы можете объявить этот массив в некоторой области данных, а затем работать с ним, вы загружаете символ data1 в регистр («адрес загрузки данных1») и используете это для извлечения содержимого памяти с этого адреса.

Или вы можете сначала поместить все числа в стек (который, вероятно, является чем-то разумным для загрузчика ОС вашего исполняемого файла), и работать в коде с указателем стека для доступа к номерам в нем.

Вы можете даже DCD некоторые значения в области CODE, поэтому эти слова будут заканчиваться между инструкциями в памяти, отображаемыми как только для чтения исполняемым загрузчиком. Вы можете прочитать эти данные, но писать им, вероятно, вызовет сбой. И, конечно же, вы не должны выполнять их как инструкции случайно (забыв поставить инструкцию ret/jump перед DCD).


без стека

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

Когда люди кодируют загрузчик, обычно они устанавливают некоторый временный стек ASAP в первых нескольких инструкциях, поэтому они могут использовать базовые функции стека до правильной настройки всей среды или загрузки ОС. Пространство для этого временного стека часто резервируется где-то в/после кода или неиспользуемое пространство памяти в соответствии с определенным состоянием машины после сброса.

Если вы находитесь на металле без ОС, обычно вся память записывается после сброса, поэтому вы можете смешать код и данные по своему усмотрению (просто прыгайте с данными, не выполняя их случайно), не используя Определения ОБЛАСТИ.

Но вы должны подумать, создаете ли вы приложение в пространстве пользователя какой-либо ОС (так что у вас есть такие вещи, как области стека и данных, и вы можете использовать их для вашего удобства), или вы создаете загрузчик код, который должен установить все для себя (более сложный, поэтому я бы предложил сначала перейти на пользовательскую территорию какой-либо ОС, причем обертка C с инициализированным клипом тоже очень удобна, поэтому вы можете называть такие вещи, как printf от ASM для удобный выход).


Как я могу работать со значениями заявленных таким образом

Это не имеет значения в машинном коде, в каком направлении были объявлены значения. Все, что имеет значение, - это если у вас есть адрес памяти, и если вы знаете структуру, то как хранятся данные. Затем вы можете работать с ними любым способом, используя любую желаемую команду. Таким образом, тело этого примера asm не изменится, если вы выделите данные в ASM, вы просто передадите указатель в качестве аргумента, как это делает C.


редактировать: некоторые примеры вслепую без тестирования, может потребоваться дальнейшее закрепление синтаксиса для работы OP (или, может быть, есть даже какая-то ошибка, и он не будет работать вообще, дайте мне знать в комментариях, если он сделал):

AREA myData, DATA, READWRITE 

SortArray 
    DCD  5, 4, 1, 3, 2, 12, 55, 64, 77, 10 
SortArrayEnd 

    AREA ARM, CODE, READONLY 

    CODE32 
    PRESERVE8 

    EXPORT __sortasmarray 

__sortasmarray 
    ; if "add r0, pc, #SortArray" fails (code too far in memory from array) 
    ; then this looks like some heavy weight way of loading any address 
    ; ldr r0, =SortArray 
    ; ldr r1, =SortArrayEnd 

    add r0, pc, #SortArray ; address of array 
    ; calculate array size from address of end 
    ; (as I couldn't find now example of thing like "equ $-SortArray") 
    add r1, pc, #SortArrayEnd 
    sub r1, r1, r0 
    mov r1, r1, lsr #2 
    ; do a direct jump instead of "bl", so __sortc returning 
    ; to lr will actually return to called of this 
    b  __sortc 

    ; ... rest of your __sortc assembly without change  

Вы можете вызвать его из кода C, как:

extern void __sortasmarray(); 

int main() 
{ 
    __sortasmarray(); 
    return 0; 
} 

Я среди других это Introducing ARM assembly language, чтобы освежить свою память ARM ассемблера, но я до сих пор беспокоит это может не работать, как есть.

Как вы можете видеть, я не изменил любой вещь в __sortc. Поскольку нет никакой разницы в доступе к стековой памяти или памяти «dcd», это одна и та же память компьютера.После того, как у вас есть адрес к определенному слову, вы можете использовать ldr/str с его адресом. __sortc получает адрес первого слова в массиве для сортировки в обоих случаях, оттуда на нем есть только память для него, без какого-либо контекста, как эта память была определена в источнике, выделена, инициализирована и т. Д. Пока это возможно для записи, это нормально для __sortc.

Таким образом, единственная связанная с «dcd» вещь - это загрузка адреса массива, а быстрый поиск примеров ARM показывает, что это может быть сделано несколькими способами, этот способ add rX, pc, #label оптимален, но работает только для диапазона + -4k ? Есть также псевдо-инструкция ADR rX, #label, делающая то же самое, и, возможно, переключение на другое в случае проблемы диапазона? Для любого диапазона это выглядит как форма ldr rX, = label, хотя я не уверен, что это псевдо-инструкция или как она работает, проверьте некоторые обучающие программы и разберите машинный код, чтобы увидеть, как он был скомпилирован.

Это зависит от вас, чтобы узнать все особенности сборки ARM и как загружать адреса массивов, в настоящий момент мне не нужна ARM ASM, поэтому я не вникнул в эти детали.

И должен быть некоторый способ определения длины массива, вместо вычисления его в коде с конечного адреса, но я не смог найти ни одного примера, и я не буду читать полные документы Ассемблера, чтобы узнать о них все его директивы (в gas я думаю, ArrayLength equ ((.-SortArray)/4) будет работать).

+0

Спасибо за ответ! Не могли бы вы привести краткий пример того, как я могу работать с массивом 'READWRITE' и писать из него + из перспективы сортировки, как менять значения. – fyfdzbgz

+0

@fyfdzbgz Я даже не знаю, какой ассемблер вы используете, и на какой платформе, и даже если бы я хотел, у меня только активная платформа ARM в форме Android NDK с ассемблером 'gas', но ваш синтаксис выглядит как какой-то ассемблер от MDK-ARM, как я связал эти документы. И я не собирал ARM-сборку за ~ 10y, и очень немногие из них тогда (я делал GameBoy Advance, но 99% кода было C++, конечно, просто проверяя вывод компилятора для упрощения C++, если компилятор запутался слишком много). Поэтому я попытаюсь добавить несколько примеров в ответ, но я сделаю их слепо без тестирования, извините. – Ped7g

+0

@fyfdzbgz Я добавил что-то, но в целом большая часть материала, который вы просите, уже есть в вашем исходном источнике, поэтому, возможно, вам нужно просто больше копаться в примерах и документах, перечитывать их несколько раз ... помните о каждом новом опыт уже прочитанных документов может иметь больше смысла, возможно, объясняя, о чем вы просите. Также проводите некоторое время в отладчике, выполняющем отдельные инструкции, отслеживая изменение состояния процессора и сравнивая это с инструкцией по инструкции для каждой инструкции, чтобы получить «почувствовать», как это работает. И перечитывать весь список инструкций время от времени, чтобы знать о них. – Ped7g

Смежные вопросы