Ldr (immediate offset)

10.42 LDR (immediate offset)

Load with immediate offset, pre-indexed immediate offset, or post-indexed immediate offset.

Syntax

where:

can be any one of:

unsigned Byte (Zero extend to 32 bits on loads.)
signed Byte ( only.
Sign extend to 32 bits.)
unsigned Halfword (Zero extend to 32 bits on loads.)
signed Halfword ( only.
Sign extend to 32 bits.)
omitted, for Word.
is an optional condition code.
is the register to load.
is the register on which the memory address is based.
is an offset. If is
omitted, the address is the contents of .
is the additional register to load for doubleword
operations.

Not all options are available in every instruction set and
architecture.

Offset ranges and architectures

The following table shows the ranges of offsets and availability of these instructions:

Table 10-10 Offsets and architectures, LDR, word, halfword, and
byte

Instruction Immediate offset Pre-indexed Post-indexed Arch.
ARM, word or byte –4095 to 4095 –4095 to 4095 –4095 to 4095 All
ARM, signed byte, halfword, or signed halfword –255 to 255 –255 to 255 –255 to 255 All
ARM, doubleword –255 to 255 –255 to 255 –255 to 255 5E
Thumb 32-bit encoding, word, halfword, signed halfword, byte, or signed byte

–255 to 4095 –255 to 255 –255 to 255 T2
Thumb 32-bit encoding, doubleword –1020 to 1020 –1020 to 1020 –1020 to 1020 T2
Thumb 16-bit encoding, word 0 to 124 Not available Not available T
Thumb 16-bit encoding, unsigned halfword 0 to 62 Not available Not available T
Thumb 16-bit encoding, unsigned byte 0 to 31 Not available Not available T
Thumb 16-bit encoding, word, is SP 0 to 1020 Not available Not available T

Notes about the Architectures column

Entries in the Architecture column indicate that the instructions are
available as follows:

All

All versions of the ARM architecture.

5E

The ARMv5TE, ARMv6*, and ARMv7 architectures.

T2

The ARMv6T2 and above architectures.

T

The ARMv4T, ARMv5T*, ARMv6*, and ARMv7 architectures.

must be different from in
the pre-index and post-index forms.

For Thumb instructions, you must not specify SP or PC for
either or .

For ARM instructions:

  • must be an even-numbered register.

  • must not be LR.

  • ARM strongly recommends that you do not use for
    .
  • must be .

Use of PC

In ARM code you can use PC for in
word instructions and PC for in
instructions.

Other uses of PC are not permitted in these ARM instructions.

In Thumb code you can use PC for in
word instructions and PC for in
instructions. Other uses of PC in these Thumb instructions are not permitted.

Use of SP

You can use SP for .

In ARM code, you can use SP for in word instructions. You
can use SP for in non-word instructions in ARM code but this
is deprecated in ARMv6T2 and above.

In Thumb code, you can use SP for in word instructions
only. All other use of SP for in these instructions are not
permitted in Thumb code.

Examples

    LDR     r8,        ; loads R8 from the address in R10.
    LDRNE   r2,!   ; (conditionally) loads R2 from a word
                            ; 960 bytes above the address in R5, and
                            ; increments R5 by 960.
Related reference

10.8 Condition code suffixes

 
For word loads, Rt can be the PC. A load to the PC causes a
branch to the address loaded. In ARMv4, bits of the address loaded must be
0b00. In ARMv5T and above, bits must not be 0b10, and if bit is 1,
execution continues in Thumb state, otherwise execution continues in ARM
state.

 
Must be divisible by 4.

 
Rt and Rn must be in the range R0-R7.

 
Must be divisible by 2.

Сегментные регистры

Сегменты — это специфические части программы, которые содержат данные, код и стек. Есть три основных сегмента:

   Сегмент кода (Code Segment или CS) — содержит все команды и инструкции, которые должны быть выполнены. 16-битный регистр сегмента кода или регистр CS хранит начальный адрес сегмента кода.

   Сегмент данных (Data Segment или DS) — содержит данные, константы и рабочие области. 16-битный регистр сегмента данных или регистр DS хранит начальный адрес сегмента данных.

   Сегмент стека (Stack Segment или SS) — содержит данные и возвращаемые адреса процедур или подпрограмм. Он представлен в виде структуры данных «Стек». Регистр сегмента стека или регистр SS хранит начальный адрес стека.

Кроме регистров CS, DS и SS существуют и другие регистры дополнительных сегментов (Extra Segment или ES), FS и GS, которые предоставляют дополнительные сегменты для хранения данных.

При написании программ на ассемблере, программе необходим доступ к ячейкам памяти. Все области памяти в сегменте относятся к начальному адресу сегмента. Сегмент начинается с адреса, равномерно делимого на десятичное 16 или на шестнадцатеричное 10. Таким образом, крайняя правая шестнадцатеричная цифра во всех таких адресах памяти равна 0, что обычно не сохраняется в сегментных регистрах.

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

Инструкция CMP

Инструкция (от англ. «COMPARE») сравнивает два операнда. Фактически, она выполняет операцию вычитания между двумя операндами для проверки того, равны ли эти операнды или нет. Используется вместе с инструкцией условного прыжка.

Синтаксис инструкции :

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

Например:

CMP DX, 00 ; сравниваем значение регистра DX с нулём
JE L7 ; если true, то переходим к метке L7
.
.
L7: …

1
2
3
4
5

CMP DX,00;сравниваемзначениерегистраDXснулём

JE  L7;еслиtrue,топереходимкметкеL7

.
.

L7…

Инструкция часто используется для проверки того, достигла ли переменная-счётчик максимального количества раз выполнения цикла или нет.

Например:

INC EDX
CMP EDX, 10 ; сравниваем, достиг ли счётчик 10 или нет
JLE LP1 ; если его значение меньше или равно 10, то тогда переходим к LP1

1
2
3

INC EDX

CMP EDX,10;сравниваем,достиглисчётчик10илинет

JLE LP1;еслиегозначениеменьшеилиравно10,тотогдапереходимкLP1

Строковые инструкции

Каждая строковая инструкция может требовать исходного операнда и операнда назначения. Для 32-битных сегментов строковые инструкции используют регистры ESI и EDI для указания на операнды источника и назначения, соответственно.

Однако, для 16-битных сегментов регистры SI и DI используются для указания на источник и место назначение.

Существует пять основных инструкций для работы со строками в Ассемблере:

    — эта инструкция перемещает 1 byte, word или doubleword данных из одной ячейки памяти в другую.

    — эта инструкция загружается из памяти. Если операндом является значение типа byte, то оно загружается в регистр AL, если типа word, то оно загружается в регистр AX, если типа doubleword, то оно загружается в регистр EAX.

    — эта инструкция сохраняет данные из регистра (AL, AX или EAX) в память.

    — эта инструкция сравнивает два элемента данных в памяти. Данные могут быть размера byte, word или doubleword.

    — эта инструкция сравнивает содержимое регистра (AL, AX или EAX) с содержимым элемента в памяти.

Каждая из инструкций выше имеет версии byte, word или doubleword, а строковые инструкции могут повторяться с использованием префикса повторения.

Эти инструкции используют пару регистров и , где регистры DI и SI содержат валидные адреса смещения, которые относятся к байтам, хранящимся в памяти. SI обычно ассоциируется с DS (сегмент данных), а DI всегда ассоциируется с ES (дополнительный сегмент).

Регистры (или ESI) и (или EDI) указывают на операнды источника и назначения, соответственно. Предполагается, что операндом-источником является (или ESI), а операндом назначения — (или EDI) в памяти.

Для 16-битных адресов используются регистры SI и DI, а для 32-битных адресов используются регистры ESI и EDI.

В следующей таблице представлены различные версии строковых инструкций и предполагаемое место операндов:

Основная инструкция Операнды в: Операция byte Операция word Операция doubleword
MOVS ES:DI, DS:SI MOVSB MOVSW MOVSD
LODS AX, DS:SI LODSB LODSW LODSD
STOS ES:DI, AX STOSB STOSW STOSD
CMPS DS:SI, ES:DI CMPSB CMPSW CMPSD
SCAS ES:DI, AX SCASB SCASW SCASD

Достоинства и недостатки

К достоинствам можно отнести следующее:

  • минимальное количество избыточного кода (использование меньшего количества команд и обращений в память). Как следствие — большая скорость и меньший размер программы;
  • непосредственный доступ к аппаратуре: портам ввода-вывода, особым регистрам процессора;
  • возможность написания самомодифицирующегося кода (то есть возможность приложению создавать или изменять часть своего кода во время выполнения, причем без необходимости программного интерпретатора);
  • максимальная «подгонка» для нужной платформы (использование специальных инструкций, технических особенностей железа).

За недостатки можно принять:

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

Синтаксис

Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако большинство разработчиков языков ассемблера придерживаются общих традиционных подходов. Основные такие стандарты — Intel-синтаксис и AT&T-синтаксис.

Общий формат записи инструкций одинаков для обоих стандартов:

Опкод — это и есть собственно ассемблерная команда, мнемоника инструкции процессору. К ней могут быть добавлены префиксы (например, повторения, изменения типа адресации). В качестве операндов могут выступать константы, названия регистров, адреса в оперативной памяти и так далее. Различия между стандартами Intel и AT&T касаются в основном порядка перечисления операндов и их синтаксиса при разных методах адресации.

Используемые команды обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных — команды процессоров и контроллеров Motorola, ARM, x86). Они описываются в спецификации процессоров.

Например, процессор Zilog Z80 наследовал систему команд Intel i8080, расширил ее и поменял некоторые команды (и обозначения регистров) на свой лад. Например, сменил Intel-команду mov на ld. Процессоры Motorola Fireball наследовали систему команд Z80, несколько ее урезав. Вместе с тем Motorola официально вернулась к Intel-командам, и в данный момент половина ассемблеров для Fireball работает с Intel-командами, а половина — с командами Zilog.

Как мыслит процессор

Что­бы понять, как рабо­та­ет Ассем­блер и поче­му он рабо­та­ет имен­но так, нам нуж­но немно­го разо­брать­ся с внут­рен­ним устрой­ством про­цес­со­ра.

Кро­ме того, что про­цес­сор уме­ет выпол­нять мате­ма­ти­че­ские опе­ра­ции, ему нуж­но где-то хра­нить про­ме­жу­точ­ные дан­ные и слу­жеб­ную инфор­ма­цию. Для это­го в самом про­цес­со­ре есть спе­ци­аль­ные ячей­ки памя­ти — их назы­ва­ют реги­стра­ми.

Реги­стры быва­ют раз­но­го вида и назна­че­ния: одни слу­жат, что­бы хра­нить инфор­ма­цию; дру­гие сооб­ща­ют о состо­я­нии про­цес­со­ра; тре­тьи исполь­зу­ют­ся как нави­га­то­ры, что­бы про­цес­сор знал, куда идти даль­ше, и так далее. Подроб­нее — в рас­хло­пе ↓

Какими бывают регистры

Обще­го назна­че­ния. Это 8 реги­стров, каж­дый из кото­рых может хра­нить все­го 4 бай­та инфор­ма­ции. Такой регистр мож­но раз­де­лить на 2 или 4 части и рабо­тать с ними как с отдель­ны­ми ячей­ка­ми.

Ука­за­тель команд. В этом реги­стре хра­нит­ся толь­ко адрес сле­ду­ю­щей коман­ды, кото­рую дол­жен выпол­нить про­цес­сор. Вруч­ную его изме­нить нель­зя, но мож­но на него повли­ять раз­лич­ны­ми коман­да­ми пере­хо­дов и про­це­дур.

Регистр фла­гов. Флаг — какое-то свой­ство про­цес­со­ра. Напри­мер, если уста­нов­лен флаг пере­пол­не­ния, зна­чит про­цес­сор полу­чил в ито­ге такое чис­ло, кото­рое не поме­ща­ет­ся в нуж­ную ячей­ку памя­ти. Он туда кла­дёт то, что поме­ща­ет­ся, и ста­вит в этот флаг циф­ру 1. Она — сиг­нал про­грам­ми­сту, что что-то пошло не так.

Фла­гов в про­цес­со­ре мно­го, какие-то мож­но менять вруч­ную, и они будут вли­ять на вычис­ле­ния, а какие-то мож­но про­сто смот­реть и делать выво­ды. Фла­ги — как сиг­наль­ные лам­пы на пане­ли при­бо­ров в само­лё­те. Они что-то озна­ча­ют, но толь­ко само­лёт и пилот зна­ют, что имен­но.

Сег­мент­ные реги­стры. Нуж­ны были для того, что­бы рабо­тать с опе­ра­тив­ной памя­тью и полу­чать доступ к любой ячей­ке. Сей­час такие реги­стры име­ют по 32 бита, и это­го доста­точ­но, что­бы полу­чить 4 гига­бай­та опе­ра­тив­ки. Для про­грам­мы на Ассем­бле­ре это­го обыч­но хва­та­ет.

Так вот: всё, с чем рабо­та­ет Ассем­блер, — это коман­ды про­цес­со­ра, пере­мен­ные и реги­стры.

Здесь нет при­выч­ных типов дан­ных — у нас есть толь­ко бай­ты памя­ти, в кото­рых мож­но хра­нить что угод­но. Даже если вы поме­сти­те в ячей­ку какой-то сим­вол, а потом захо­ти­те рабо­тать с ним как с чис­лом — у вас полу­чит­ся. А вме­сто при­выч­ных цик­лов мож­но про­сто прыг­нуть в нуж­ное место кода.

Ассемблер — программирование или искусство?

Скажем так, все зависит от того, в чьих руках он находится. Ассемблер — это первичный элемент мира процессора, из сочетаний этих элементов складывается его душа, его самосознание. Подобно тому, как вся музыка, написанная в истории человечества, состоит из сочетаний семи нот, так и сочетание ассемблерных команд наполняет компьютерный мир цифровой жизнью. Кто знает лишь три аккорда — это «попса», кому же известна вся палитра — это классика.

Почему же наука так жаждет проникнуть в квантовые глубины и захватить в свои руки неуловимый первичный кирпичик материи? Чтобы получить над ней власть, изменять ее по своей воле, стать на уровень Творца Вселенной. В чьи руки попадет такая власть — это еще вопрос. В отличие от науки, в мире программирования тайн нет, нам известны кирпичики, его составляющие, а следовательно, и та власть над процессором, которую нам дает знание ассемблера.

Чтобы программирование на языке ассемблера поднялось на уровень искусства, нужно постичь его красоту, скрывающуюся за потоком единиц и нулей. Как и в любой отрасли человеческой деятельности, в программировании можно быть посредственностью, а можно стать Мастером. И то и другое отличает степень культуры, образования, труда и, главное, то, сколько души автор вкладывает в свое творение.

Ассемблер и терминатор

Не так давно Джеймс Кэмерон выпустил в свет 3D-версию второго «Терминатора», и в качестве интересного исторического факта можно отметить один любопытный момент из жизни киборга-убийцы…

Кадр из фильма «Терминатор»

Здесь мы видим «зрение» терминатора, а слева на нем отображается ассемблерный листинг. Судя по нему, знаменитый Уничтожитель работал на процессоре MOS Technology 6502 либо на MOS Technology 6510. Этот процессор впервые был разработан в 1975 году, использовался на компьютерах Apple и, помимо всего прочего, на знаменитых игровых приставках того времени Atari 2600 и Nintendo Entertainment System (у нас более известной как Dendy). Имел лишь три 8-разрядных регистра: А-аккумулятор и два индексных регистра X и Y. Такое малое их количество компенсировалось тем, что первые 256 байт оперативной памяти (так называемая нулевая страница) могли адресоваться специальным образом и фактически использовались в качестве 8-разрядных или 16-разрядных регистров. У данного процессора было 13 режимов адресации на всего 53 команды. У терминатора идет цепочка инструкций LDA-STA-LDA-STA… В семействе 6502 программы состояли чуть менее чем полностью из LDA/LDY/LDX/STA/STX/STY:

Чтение и запись в порты ввода-вывода также выполнялись этими командами, и программа терминатора имеет вполне осмысленный вид, а не представляет собой бестолковую фантазию сценариста: MOS Technology 6502 / Система команд.

Архитектуры RISC

MCS-51

MCS-51 (Intel 8051) — классическая архитектура микроконтроллера. Для неё существует кросс-ассемблер ASM51, выпущенный корпорацией MetaLink.

Кроме того, многие фирмы-разработчики программного обеспечения, такие, как IAR или Keil, представили свои варианты ассемблеров. В ряде случаев применение этих ассемблеров оказывается более эффективным благодаря удобному набору директив и наличию среды программирования, объединяющей в себе профессиональный ассемблер и язык программирования Си, отладчик и менеджер программных проектов.

Пример программы на языке ASM-51 для микроконтроллера AT89S52:

 
mov SCON, #50h
mov TH1, #0FDh
orl TMOD, #20h
setb TR1
again:
  clr RI
  jnb RI, $
  mov A, SBUF
  jnb RI, $
  clr TI
  mov SBUF, A
  jnb TI, $
sjmp again

Данная программа («Эхо») отправляет обратно полученный символ, через последовательный порт UART.

AVR

На данный момент для AVR существуют 4 компилятора производства Atmel (AVRStudio 3, AVRStudio 4, AVRStudio 5 и AVRStudio 6, AVRStudio 7).

В рамках проекта AVR-GCC (он же WinAVR) существует компилятор avr-as (это портированный под AVR ассемблер GNU as из GCC).

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

Платные компиляторы: IAR (EWAVR), CodeVisionAVR, Imagecraft. Данные компиляторы поддерживают языки Assembler и C, а IAR ещё и C++.

Существует компилятор с языка BASIC — BASCOM, также платный.

ARM

Поставщик IDE Компилятор Поддерживаемые языки Условия использования
Си/С++/Assembler Shareware (не более 32kb)
Си/С++/Assembler Commercial
Си/С++/Assembler.
Си/С++/Assembler
Битовые операции

Си:

z = (a << 2) | (b & 15);

ASM:

ADR r4,a ; get address for a
LDR r0,[r4 ; get value of a
MOV r0,r0,LSL#2 ; perform shift
ADR r4,b ; get address for b
LDR r1,[r4 ; get value of b
AND r1,r1,#15 ; perform AND
ORR r1,r0,r1 ; perform OR
ADR r4,z ; get address for z
STR r1,[r4 ; store value for z

Си:

if (i == )
{
    i = i + 10;
}

ASM:

@(переменная i находится в регистре R1)
SUBS R1, R1, #0
ADDEQ R1, R1, #10
Циклы

Си:

for ( i =  ; i < 15 ; i++)
{
    j = j + j;
}

ASM:

      SUB R0, R0, R0 ; i -> R0 and i = 0
start CMP R0, #15 ; is i < 15?
      ADDLT R1, R1, R1 ; j = j + j
      ADDLT R0, R0, #1 ; i++
      BLT start

PIC

Пример программы на языке ассемблера для микроконтроллера PIC16F628A (архитектура PIC):

 
        LIST    p=16F628A
         __CONFIG 0309H 
 
STATUS  equ     0x003
TRISB   equ     0x086
PORTB   equ     0x006
RP0     equ     5
        org  
        goto start
start:
        bsf     STATUS,RP0             
        movlw   .00      
        movwf   TRISB                    
        bcf     STATUS,RP0        
led
        movlw   .170   
        movwf   PORTB
        goto    led
end

MSP430

Пример программы на языке Assembler для микроконтроллера MSP430G2231 (архитектура MSP, в среде Code Composer Studio):

 
 .cdecls C,LIST,  "msp430g2231.h"
;------------------------------------------------------------------------------
            .text                           ; Program Start
;------------------------------------------------------------------------------
RESET       mov.w   #0280h,SP               ; Initialize stackpointer
StopWDT     mov.w   #WDTPW+WDTHOLD,&WDTCTL  ; Stop WDT
SetupP1     bis.b   #001h,&P1DIR            ; P1.0 output
                                            ;				          			
Mainloop    bit.b   #010h,&P1IN             ; P1.4 hi/low?
            jc      ON                      ; jmp--> P1.4 is set
                                            ;
OFF         bic.b   #001h,&P1OUT            ; P1.0 = 0 / LED OFF
            jmp     Mainloop                ;
ON          bis.b   #001h,&P1OUT            ; P1.0 = 1 / LED ON
            jmp     Mainloop                ;
                                            ;
;------------------------------------------------------------------------------
;           Interrupt Vectors
;------------------------------------------------------------------------------
            .sect   ".reset"                ; MSP430 RESET Vector
            .short  RESET                   ;
            .end

Синтаксис

Синтаксис языка ассемблера определяется системой команд конкретного процессора.

Набор команд

  • Команды пересылки данных (mov, lea и т. д.)
  • Арифметичекие команды (add, sub, imul и т. д.)
  • Логические и побитовые операции (or, and, xor, shr и т. д.)
  • Команды управления ходом выполнения программы (jmp, loop, ret и т. д.)
  • cbne — перейти, если не равно
  • dbnz — декрементировать, и если результат ненулевой, то перейти
  • cfsneq — сравнить, и если не равно, пропустить следующую команду

Инструкции

Типичный формат записи команд:
<source lang=»asm»> опкод </source>

  • Если изначально существовало два стандарта записи мнемоник (система команд была наследована от процессора другого производителя).

Например, процессор наследовал систему команд , расширил ее и поменял мнемоники (и обозначения регистров) на свой лад. Процессоры наследовали систему команд Z80, несколько её урезав. Вместе с тем, Motorola официально вернулась к мнемоникам Intel. И в данный момент половина ассемблеров для Fireball работает с интеловскими мнемониками, а половина с мнемониками Zilog.

Директивы

Программа на ассемблере может содержать директивы: инструкции, не переводящиеся непосредственно в машинные команды, а управляющие работой компилятора. Набор и синтаксис их значительно разнятся и зависят не от аппаратной платформы, а от используемого транслятора (порождая диалекты языков в пределах одного семейства архитектур). В качестве «джентельменского набора» директив можно выделить следующие:

  • определение данных (констант и переменных)
  • управление организацией программы в памяти и параметрами выходного файла
  • задание режима работы компилятора

Операции пересылки данных

Мнемоника Описание Операция Флаги
MOV Rd, Rr Пересылка между регистрами Rd ← Rr
MOVW Rd, Rr Пересылка между парами регистров R(d +1):Rd ← R(r+1):Rr
LDI Rd, K Загрузка константы в регистр Rd ← K
LD Rd, X Косвенное чтение Rd ←
LD Rd, X+ Косвенное чтение с пост-инкрементом Rd ← , X ← X + 1
LD Rd, -X Косвенное чтение с пред-декрементом X ← X — 1, Rd ←
LD Rd, Y Косвенное чтение Rd ←
LD Rd, Y+ Косвенное чтение с пост-инкрементом Rd ← , Y ← Y + 1
LD Rd, -Y Косвенное чтение с пред-декрементом Y ← Y — 1, Rd ←
LDD Rd, Y+q Косвенное чтение со смещением Rd ←
LD Rd, Z Косвенное чтение Rd ←
LD Rd, Z+ Косвенное чтение с пост-инкрементом Rd ← , Z ← Z + 1
LD Rd, -Z Косвенное чтение с пред-декрементом Z ← Z — 1, Rd ←
LDD Rd, Z+q Косвенное чтение со смещением Rd ←
LDS Rd, A Непосредственное чтение из ОЗУ Rd ←
ST X, Rr Косвенная запись ← Rr
ST X+, Rr Косвенная запись с пост-инкрементом ← Rr, X ← X + 1
ST -X, Rr Косвенная запись с пред-декрементом X ← X — 1, ← Rr
ST Y, Rr Косвенная запись ← Rr
ST Y+, Rr Косвенная запись с пост-инкрементом ← Rr, Y ← Y + 1
ST -Y, Rr Косвенная запись с пред-декрементом Y ← Y — 1, ← Rr
STD Y+q, Rr Косвенная запись со смещением ← Rr
ST Z, Rr Косвенная запись ← Rr
ST Z+, Rr Косвенная запись с пост-инкрементом ← Rr, Z ← Z + 1
ST -Z, Rr Косвенная запись с пред-декрементом Z ← Z — 1, ← Rr
STD Z+q, Rr Косвенная запись со смещением ← Rr
STS A, Rr Непосредственная запись в ОЗУ ← Rr
LPM Загрузка данных из памяти программы R0 ← {Z}
LPM Rd, Z Загрузка данных из памяти программы в регистр Rd ← {Z}
LPM Rd, Z+ Загрузка данных из памяти программы с пост-инкрементом Z Rd ← {Z}, Z ← Z + 1
SPM Запись в программную память {Z} ← R1:R0
IN Rd, P Пересылка из I/O-регистра в регистр Rd ← P
OUT P, Rr Пересылка из регистра в I/O-регистр P ← Rr
PUSH Rr Сохранение регистра в стеке STACK ← Rr
POP Rd Извлечение регистра из стека Rd ← STACK

Почему следует изучать язык ассемблера?

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

Так зачем же тратить время на его изучение? По ряду веских причин, и вот одна из них: ассемблер — это краеугольный камень, на котором покоится все бесконечное пространство программирования, начиная от рождения первого процессора. Каждый физик мечтает разгадать тайну строения вселенной, найти эти загадочные первичные неделимые (низкоуровневые) элементы, из которых она состоит, не удовлетворяясь лишь смутным о том представлением квантовой теории. Ассемблер же и есть та первичная материя, из которой состоит вселенная процессора. Он — тот инструмент, который дает человеку способность мыслить в терминах машинных команд. А подобное умение просто необходимо любому профессиональному программисту, даже если никогда в жизни он не напишет ни единой ассемблерной строчки. Нельзя отрицать того, что невозможно стать математиком, совершенно не имея понятия об элементарной арифметике. На каком бы языке вы ни писали программы, необходимо хотя бы в общих чертах понимать, что конкретно будет делать процессор, исполняя ваше высочайшее повеление. Если такого понимания нет, программист начинает бездумно применять все доступные операции, совершенно не ведая, что на самом деле он творит.

Вообще, профессиональный пользователь компьютера, системный ли администратор, или программист, может позволить себе что-то не знать, но ни в коем случае не может позволить не понимать сути происходящего, как устроена вычислительная система на всех ее уровнях, от электронных логических схем до громоздких прикладных программ. А непонимание чего-то влечет за собой ощущение в глубине подсознания некоей загадочности, непостижимого таинства, происходящего по мановению чьей-то волшебной палочки. Такое ощущение для профессионала недопустимо категорически. Он просто обязан быть уверен вплоть до глубинных слоев подсознания, что то устройство, с которым он имеет дело, ничего волшебного и непознаваемого собой не представляет.

Иными словами, до тех пор пока существуют процессоры, ассемблер будет необходим.

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

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

10.133 STR (immediate offset)

Store with immediate offset, pre-indexed immediate offset, or post-indexed immediate offset.

Syntax

where:

can be any one of:

Byte.
Halfword.
omitted, for Word.
is an optional condition code.
is the register to store.
is the register on which the memory address is based.
is an offset. If is
omitted, the address is the contents of .
is the additional register to store for doubleword
operations.

Not all options are available in every instruction set and
architecture.

Offset ranges and architectures

The following table shows the ranges of offsets and availability of this
instruction:

Table 10-15 Offsets and architectures, STR, word, halfword, and byte

Instruction Immediate offset Pre-indexed Post-indexed Arch.
ARM, word or byte –4095 to 4095 –4095 to 4095 –4095 to 4095 All
ARM, halfword –255 to 255 –255 to 255 –255 to 255 All
ARM, doubleword –255 to 255 –255 to 255 –255 to 255 5E
Thumb 32-bit encoding, word, halfword, or
byte
–255 to 4095 –255 to 255 –255 to 255 T2
Thumb 32-bit encoding, doubleword –1020 to 1020 –1020 to 1020 –1020 to 1020 T2
Thumb 16-bit encoding, word 0 to 124 Not available Not available T
Thumb 16-bit encoding, halfword 0 to 62 Not available Not available T
Thumb 16-bit encoding, byte 0 to 31 Not available Not available T
Thumb 16-bit encoding, word, is SP 0 to 1020 Not available Not available T

Notes about the Architecture column

Entries in the Architecture column indicate that the instructions are
available as follows:

All

All versions of the ARM architecture.

5E

The ARMv5TE, ARMv6*, and ARMv7 architectures.

T2

The ARMv6T2 and above architectures.

T

The ARMv4T, ARMv5T*, ARMv6*, and ARMv7 architectures.

must be different from in
the pre-index and post-index forms.

For Thumb instructions, you must not specify SP or PC for
either or .

For ARM instructions:

  • must be an even-numbered register.

  • must not be LR.

  • ARM strongly recommends that you do not use for
    .
  • must be .

Use of PC

In ARM instructions you can use PC for in word
instructions and PC for in instructions
with immediate offset syntax (that is the forms that do not writeback
to the ). However, this is deprecated
in ARMv6T2 and above.

Other uses of PC are not permitted in these ARM instructions.

In Thumb code, using PC in instructions
is not permitted.

Use of SP

You can use SP for .

In ARM code, you can use SP for in word instructions. You
can use SP for in non-word instructions in ARM code but this
is deprecated in ARMv6T2 and above.

In Thumb code, you can use SP for in word instructions
only. All other use of SP for in this instruction is not
permitted in Thumb code.

Example

    STR     r2,   ; consta-struc is an expression
                                    ; evaluating to a constant in 
                                    ; the range 0-4095.

Прыжок с условием

Если в условном прыжке выполняется указанное условие, то точка выполнения программы переносится в указанную инструкцию. Существует множество инструкций условного прыжка в зависимости от условия и данных.

Ниже приведены инструкции условного прыжка, используемые для данных со знаком в арифметических операциях:

Инструкция Описание Тестируемые флаги
JEJZ Jump Equal (равно) или Jump Zero (ноль) ZF
JNE/JNZ Jump Not Equal (не равно) или Jump Not Zero (не ноль) ZF
JG/JNLE Jump Greater (больше) или Jump Not Less/Equal (не меньше/равно) OF, SF, ZF
JGE/JNL Jump Greater/Equal (больше/равно) или Jump Not Less (не меньше) OF, SF
JL/JNGE Jump Less (меньше) или Jump Not Greater/Equal (не больше/равно) OF, SF
JLE/JNG Jump Less/Equal (меньше/равно) или Jump Not Greater (не больше) OF, SF, ZF

В следующей таблице приведены инструкции условного прыжка, используемые для данных без знака в логических операциях:

Инструкция Описание Тестируемые флаги
JE/JZ Jump Equal (равно) или Jump Zero (ноль) ZF
JNE/JNZ Jump Not Equal (не равно) или Jump Not Zero (не ноль) ZF
JA/JNBE Jump Above (больше) или Jump Not Below/Equal (не меньше/равно) CF, ZF
JAE/JNB Jump Above/Equal (больше/равно) или Jump Not Below (не меньше) CF
JB/JNAE Jump Below (меньше) или Jump Not Above/Equal (не больше/равно) CF
JBE/JNA Jump Below/Equal (меньше/равно) или Jump Not Above (не больше) AF, CF

Следующие инструкции условного прыжка имеют специальное использование и проверяют значение флагов:

Инструкция Описание Тестируемые флаги
JCXZ Jump если CX равно Zero none
JC Jump если Carry (перенос) CF
JNC Jump если No Carry (нет переноса) CF
JO Jump если Overflow (переполнение) OF
JNO Jump если No Overflow (нет переполнения) OF
JP/JPE Jump Parity или Jump Parity Even (если чётность) PF
JNP/JPO Jump No Parity или Jump Parity Odd (если нечётность) PF
JS Jump Sign (отрицательное значение) SF
JNS Jump No Sign (положительное значение) SF

Пример синтаксиса набора инструкций типа :

CMP AL, BL
JE EQUAL
CMP AL, BH
JE EQUAL
CMP AL, CL
JE EQUAL
NON_EQUAL: …
EQUAL: …

1
2
3
4
5
6
7
8

CMP AL,BL

JE EQUAL

CMP AL,BH

JE EQUAL

CMP AL,CL

JE EQUAL

NON_EQUAL…

EQUAL…

В качестве примера, рассмотрим следующую программу, которая определяет и выводит на экран наибольшую из трёх целочисленных переменных:

section .text
global _start ; должно быть объявлено для использования gcc

_start: ; сообщаем линкеру входную точку
mov ecx,
cmp ecx,
jg check_third_num
mov ecx,

check_third_num:

cmp ecx,
jg _exit
mov ecx,

_exit:

mov , ecx
mov ecx,msg
mov edx, len
mov ebx,1 ; файловый дескриптор (stdout)
mov eax,4 ; номер системного вызова (sys_write)
int 0x80 ; вызов ядра

mov ecx,largest
mov edx, 2
mov ebx,1 ; файловый дескриптор (stdout)
mov eax,4 ; номер системного вызова (sys_write)
int 0x80 ; вызов ядра

mov eax, 1
int 80h

section .data

msg db «The largest digit is: «, 0xA,0xD
len equ $- msg
num1 dd ’47’
num2 dd ’22’
num3 dd ’31’

segment .bss
largest resb 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

section.text

global_start;должнобытьобъявленодляиспользованияgcc

_start;сообщаемлинкерувходнуюточку

mov   ecx,num1

cmp   ecx,num2

jg    check_third_num

mov   ecx,num2

check_third_num

cmp   ecx,num3

jg    _exit

mov   ecx,num3

_exit

movlargest,ecx

mov   ecx,msg

mov   edx,len

mov   ebx,1;файловыйдескриптор(stdout)

mov   eax,4;номерсистемноговызова(sys_write)

int0x80;вызовядра

mov   ecx,largest

mov   edx,2

mov   ebx,1;файловыйдескриптор(stdout)

mov   eax,4;номерсистемноговызова(sys_write)

int0x80;вызовядра

mov   eax,1

int80h

section.data

msg db»The largest digit is: «,0xA,0xD

len equ$-msg

num1 dd’47’

num2 dd’22’

num3 dd’31’

segment.bss

largest resb2

Результат выполнения программы выше:

Регистры-указатели

Регистрами-указателями являются 32-битные регистры EIP, ESP и EBP и соответствующие им 16-битные регистры IP, SP и BP. Есть три категории регистров-указателей:

   Указатель на инструкцию или команду (Instruction Pointer или IP) — 16-битный регистр IP хранит смещение адреса следующей команды, которая должна быть выполнена. IP в сочетании с регистром CS (как CS:IP) предоставляет полный адрес текущей инструкции в сегменте кода.

   Указатель на стек (Stack Pointer или SP) — 16-битный регистр SP обеспечивает значение смещения в программном стеке. SP в сочетании с регистром SS (SS:SP) относится к текущей позиции данных или адреса в программном стеке.

   Базовый указатель (Base Pointer или BP) — 16-битный регистр BP используется в основном при передаче параметров в подпрограммы. Адрес в регистре SS объединяется со смещением в BP, чтобы получить местоположение параметра. BP также можно комбинировать с DI и SI в качестве базового регистра для специальной адресации.

Строки в Ассемблере

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

   явное содержание длины строки;

   использование сигнального символа.

Мы можем явно хранить длину строки, используя символ счётчика местоположения , который представляет текущее значение счётчика местоположения строки.

Например:

msg db ‘Hello, world!’,0xa ; наша строка
len equ $ — msg ; длина нашей строки

1
2

msg  db’Hello, world!’,0xa;нашастрока

len  equ$-msg;длинанашейстроки

Символ указывает на byte после последнего символа строковой переменной . Следовательно, указывает на длину строки. Мы также можем написать:

msg db ‘Hello, world!’,0xa ; наша строка
len equ 13 ; длина нашей строки

1
2

msg db’Hello, world!’,0xa;нашастрока

len equ13;длинанашейстроки

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

Например:

message DB ‘I am loving it!’, 0

1 message DB’I am loving it!’,

Типы прыжков

Есть 2 типа выполнения условий в ассемблере:

   Прыжок без условия (или ещё «безусловный прыжок») — выполняется инструкцией . Выполнение данной инструкции часто включает передачу управления в адрес инструкции, которая не следует за выполняемой в настоящее время инструкцией. Результатом передачи управления может быть выполнение нового набора инструкций или повторное выполнение текущих инструкций.

   Прыжок с условием (или ещё «условный прыжок») — выполняется с помощью инструкций типа и зависит от самого условия. Условные инструкции, изменяя значение смещения в регистре , передают управление, прерывая последовательный поток выполнения кода.

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

Оцените статью:
Оставить комментарий