ARM 어셈블리에 대해 설명됀 사이트와 예제(Asm과 C 비교)

Posted by 빵빵빵
2011/02/22 15:27 전산(컴퓨터)/Mobile-CE&PPC



http://kkamagui.springnote.com/pages/432792


http://downrg.com/i/entry/417

※ 용어 정의
     Rd: Destination Register   /   Rn: Operand1 Register   /   Rm: Operand2 Register
     <cond>: Execution Condition code
     <S>: S-Suffix - Status Update Suffix - SPSR의 값을 CPSR로 불러와서 Status를 Update
     <!> : ! - Suffix - Writeback Suffix - [,]내의 선처리 연산 수행 후 값을 갱신
     <Operand2>: Operand2가 가질 수 있는 형식
          ㄱ. #Immediate: 32bit  명령에서 Immediate값은 8-bit pattern의 짝수 shift 값 만을 허용
          ㄴ. Rm{, shift연산 #immediate}: Register(Rm)값에 #immediate 값으로 Shift 연산

      
                 § Shift 연산의 종류
               - asr(Arithmetic Shift Right): Immediate의 값 만큼 right shift, 앞에 bit는 Sign Extension
               - lsr(Logical Shift Right): Immediate의 값 만큼 right shift, 앞에 bit는 0으로 채움
               - lsl(Logical Shift Left): Immediate의 값 만큼 left shift, 뒤에 bit는 0으로 채움
               - ror(ROtate Right): Immediate의 값 만큼 rotate right, rotate후 bit 0값은 carry에 저장
               - rrx(Rotate Right eXtend): rrx는 1bit 씩 rotate right, bit 0값은 carry에 저장

1. 데이터 처리 명령(General Data Processing Instruction)

     1.1 산술 연산
Syntax: add<cond><S> Rd, Rn, <Operand2>

          add: Rd := Rn + <Operand2>
          sub: Rd := Rn - <Operand2>
          adc(ADd with Carry), sbc(SuBtract with Carry): Carry를 포함한 add, sub 연산
       
          rsb(Reverse SuBtract): Rd := <Operand2> - Rn
          rsc(Reverse Subract with Carry): Carry를 포함한 역 sub 연산

     1.2 논리 연산
Syntax: and<cond><S> Rd, Rn, <Operand2>

          and: Rd := Rn & <Operand2>
          orr:  Rd := Rn | <Operand2>
          eor: Rd := Rn ^ <Operand2>
          bic: Rd := Rn & !<Operand2>
     1.3 Register 값 저장
Syntax: mov<cond><S> Rd, <Operand2>

          mov: Rd := <Operand2>
          mvn: Rd := !<Operand2>

     1.4 비교
Syntax: cmp<cond><S> Rn, <Operand2>

          cmp: Rn값에서 Opeand2값을 빼서 그 결과를 Status flag에 반영, SUBS와 동일한 명령
          cmn: Rn값에서 Operand2값을 더해서 그 결과를 Status flag에 반영, ADDS와 동일한 명령

          tst: Rn과 Opearand2를 bit and 연산을 수행해서 그 결과를 Status flag에 반영, ANDS와 동일한 명령
          teq: Rn과 Operand2를 bit xor 연산을 수행해서 그 결과를 Status flag에 반영, EORS와 동일한 명령

2. 메모리 접근 명령(Memory Accesss Instruction)

          Syntax: ldr<cond><B> Rd, label
                       ldr<cond><B><T> Rd, [Rn]
                       ldr<cond><B> Rd, [Rn, FlexOffset]<!>         ;Pre-Indexed<Auto-Indexing>
                       ldr<cond><B><T> Rd, [Rn], FlexOffset       ;Post-Indexed

          <B>: B Suffix가 있을 경우 8-bit Unsigned byte 단위로 Access, 없을 경우 32-bit word로 Access
          <T>: T suffix가 있을 경우 Processor가 User mode에서 memory access 처리
          FlexOffset:
               ㄱ.#Immediate: -4095 부터 -4096사이의 상수 값
               ㄴ.{-}Rm{, shift연산}: Rm은 음의 부호를 가질 수 있으며, Rm의 Shift 연산도 가능함

     2.1 Load 또는 Store 명령 예제

          ldr r0, [r1]: r1에 저장된 주소를 이용해서 메모리로부터 r0로 값을 불러옴
          str r0, [r1], #4: r0의 값을 메모리의 r1의 주소에 저장하고 r1을 +4함.
          참고) 부호가 있는 Halfword, Byte로 읽을 때는 SH(Signed Halfword), SB(Signed Byte) <--(ldr only)
                  Unsigned Halfword로 읽거나 저장할 때는 H를 사용.
                  Doubleword의 경우 D 를 사용, 이 때의 Offset은 {-}Rm 만 허용함.

     2.2 Multiple Load 또는 Store 명령

Syntax: ldm<cond><addrmode> Rn<!>, {reglist}<^>

          <addrmode>: address mode에는 총 8가지가 있으며, 4가지는 address의 연상 방식에 따른
                                구분이며 4가지는 stack의 특성에 따른 구분이다.
              - IA(Increment Address after each transfer), - IB(Increment Address after each transfer)
              - DA(Decrement Address after each transfer), - DB(Decrement Address after each transfer)

              - FD(Full descending stack): stack의 주소에 data가 저장이 된 상태이고, 주소가 감소하면서 저장
              - ED(Emtpy descending stack): stack의 주소에 data가 없는 상태이고, 주소가 감소하면서 저장
              - FA(Full ascending stack): stack의 주소에 data가 저장이 된 상태이고, 주소가 증가하면서 저장
              - EA(Emtpy ascending stack): stack의 주소에 data가 없는 상태이고, 주소가 증가하면서 저장

          <!>: ! - Suffix가 있을 경우 마지막 주소(최종으로 이동한 주소)를 Rn에 저장함
          <^>: SPSR의 값을 CPSR에 넣어줌, S-Suffix와 동일한 기능을 수행함.

          ldm: Rn으로 부터 reglist에 지정한 register 수 만큼 값을 불러옴
          stm: reglist에 있는 register의 값들을 Rn에 저장함.

          [주의] Reglist에 지정한 Register의 순서와 상관없이 Register의 번호가 낮은 값이
                    메모리의 낮은 주소에 저장 또는 읽어진다. reglist는 'r1,r2,r3' 또는 'r1-r3'으로 표현
          [자주 사용되는 형식] STMFD sp!, {r4-r7,lr} / LDMFD sp!, {r4-r7,pc}

3. 분기 명령(Branch Instruction)

Syntax
: b<cond> label

     b: label이 있는 주소로 branch(PC값에 label의 주소를 입력)
     bl: 다음 명령의 주소를 lr에 저장하고, b와 같이 label의 주소로 branch

4. 기타 명령어
     4.1 Software Interrupt
Syntax: swi<cond> Immediate_24bit

          swi: 지정한 번호를 갖는 Software Interrupt를 발생시킴, 해당 번호에 맞는 SWI vector로 branch
               (Software Interrupt가 걸리면 프로세서의 모드는 Supervisor로 변경됨)

     4.2 PSR Access
Syntax: mrs<cond> Rd, psr

                    psr에 지정한 값(cpsr 또는 spsr)로 부터 값을 불러와서 Rd에 저장 (Register <- PSR)

Syntax: msr<cond> psr_(field), #Immediate_8bit
msr<cond> psr_fields, Rm      

                    Register(Rm)의 값 또는 8bit Immediate값을 psr(cpsr 또는 spsr)에 저장 (Register -> PSR)
                    (field): f, s, x, c 값이 선택적으로 올 수 있음. 지정한 field 영역에만 값을 저장함.

          [주의] 프로세서가 User 또는 System mode일 때는 SPSR에 엑세스 하지 말아야 한다.
          [자주 사용되는 형식] msr CPSR_c,r0
5. 상태 플래그와 실행 조건 코드(Status Flags & Execution Condition Codes)
     N: 연산 결과가 음의 값을 가질 때 Set '1'
     Z: 연산 결과가 영일 때 Set '1'
     C: 연산 결과가 캐리(Carry)를 가질 때 Set '1'
     V: 연산 결과 오버플로우(Overflow)를 발생시킬 때 Se

<ARM Instructioin Set>


     ① opcode<cond><S> Rd, Rn, #Immediate
     ② opcode<cond><S> Rd, Rn, Rm OP #Imm
     ③ opcode<cond><S> Rd, Rn, Rm OP Rs
          - cmp, cmn 명령에서는 Rd는 무조건 '0' 값을 넣어줘야 함.(SBZ(Should Be Zero))

     ④ opcode<cond> Rd, Rn, #Immediate
     ⑤ opcode<cond> Rd, Rn, Rm OP #Imm
     ⑥ opcode<cond> Rd, <address>
     ⑦ opcode<cond><addrmode> Rm, Register_List^
     ⑧ opcode<cond><addrmode> Rm<!>, Register_List
     ⑨ opcode<cond><addrmode> Rm<!>, Register_List^
          - P='1' Pre, P='0' Post / U='1' Increment, U='0' Decrement / B='1' Byte load, B='0' Word load /
            W='1' Write-back(Auto-Index) W='0' / L='1' opcode는 ldr, L= '0' str /
            I='1' Addr_mode가 모두 Offset field I='0' 앞에 Addr_mode는 '0' 뒤에 Addr_mode는 Rm /
            S='1' Signed, S='0' Unsigned / H='1' Half Word, H='0' Word or Byte

     ⑩ b<cond> #Target Address(24bit Offset) - L의 값이 '1'이면 bl 명령

     ⑪ SWI #SWI Number

    ⑫ mrs<cond><S> Rd, PSR
     ⑬ msr<cond><S> PSR_<Field_Mask>, Rm
     ⑭ msr<cond><S> PSR_f, #Immediate
          - S의 값이 '1'이면 SPSR에서, '0'이면 CPSR.
          - SBO(Should Be One) 영역은 '1'로, SBZ(Should Be Zero) 영역은 '0'의 값을 넣어줘야 함

<ARM Assembly 명령어 정리표>
<참고자료>
  - ARM Developer Suite 1.2 Assembler Guide(ARM DUI 0068B):
    http://infocenter.arm.com/help/topic/com.arm.doc.dui0068b/DUI0068.pdf
  - ARM Asssembly Language Programming: http://www.arm.com/miscPDFs/9658.pdf
  - kkamagui의 프로그래밍 작업실 ARM 어셈블리: http://kkamagui.springnote.com/pages/432792
  - ARM Instruction Quick Finder: http://www.heyrick.co.uk/assembler/qfinder.html
  - ARM Reference - rE Ejected: http://re-eject.gbadev.org/ =>ARM_Reference-rE.Ejected.pdf 자료 출처



"Embedded" 카테고리의 다른 글











추가 ARM Assembly 관련 내용
; generated by Thumb C Compiler, ADS1.2 [Build 805]
; commandline [-O2 -S -IC:\apps\ADS12\INCLUDE]
        CODE16                                                 1. 일단 Thumb mode compile되었군요.
        AREA ||.text||, CODE, READONLY           2. Section 이름은 ||.text||이고 code네요.
calc PROC                                                      3. 함수 이름이 calc라는 걸로 구현되어 있나 봐여
        PUSH     {r0-r7,lr}                                 4. 어디선가 불리면서 r0~r6을 stack에 넣고, lr도 넣네요.
        LDR      r6,|L1.32|                                  5. r6에 |L1.32|의 주소를 넣고서..
        MOV      r5,r0                                         6. 뭔지 모르겠지만 r0는 argument로 받았고
                                                                          이녀석을 r5에 복사하네요?
        MOV      r4,#0                                        7. r4에는 0을 넣고요.
        MOV      r7,#2                                        8. r6에는 2를 넣습니다.
|L1.10|
        LSL      r5,r5, r7                                          9. r5를 r7만큼 shift해서 r5에 넣고
        ADD      r4,r4,r5                                     10. r4에 다시 r4와 r5를 더한 것을 넣어요.
        MOV      r0,r4                                         11. r4을 r0에 넣고서
        LDR      r1,[r6,#4]  ; data                       12. r6가 가르키는 곳에서 4만큼 더한 곳의 값을 r1에..
        BL       manual                                          13. manual이라는 함수로 r0와 r1의 값을 가지고 jump
                                                                            LR에는 CMP r0, #0를 넣고서..
        CMP      r0,#0                                         14. manul의 return값이 0인지 확인해서
        BNE      |L1.10|                                       15. 0이 아니면 |L1.10|으로 jump
        MOV      r0,r4                                          16. 이제 돌아가기 위해서 r4를 r0에 넣고
        POP      {r3-r7,pc}                                  17. 이 함수를 부른 곳으로 돌아간다 .
        DCW      0000
|L1.32| DATA
        DCD      data
        ENDP
 
        AREA ||.data||, DATA, ALIGN=2
||.data$0||
data
        DCB      0x0000000a
        DCB      0x00000014
        DCB      0x0000001e
        DCB      0x0000002

사용자 삽입 이미지
일단은 뭔가를 loop를 돌고 있는데, manual 이라는 함수의 결과 값이 0이면 계속 loop를 도는 형태로서, 그 loop안에서는 r5가 계속 2의 좌승 형태로 늘어나면서 r4에 저장되는 형태를 취하고 있고요. manual의 argument는 계속 저장되는 r4와 특정 memory 영역에서 가져온 값인 r1, 2개를
갖습니다. 또한 이 함수는 return값으로 계속 저장된 값 r4를 최종적으로 돌려주게 되어 있는 형태 입니다. 대충 감 오시는 지요?
 
이 녀석을 대충의 c code로 다시 reverse engineering해 보면 다음과 같이 상상해 볼 수 있을 것입니다.
 
byte data[] = { 10, 20, 30, 40};
 
int calc (int a)
{
    int sum=0;                          //아마도 r4
 
    while (1)
    {
       a = a^4;                             // 여기에서 재미있는 사실은 ^4할 때마다 <<2를 해주면 같은 효과
                                                   // 아마도 r5
       sum = sum + a ;                // r4 = r4 + r5
      
       if (manual (sum,data[1]))  // r4와 r6이 가르키는 이상한 data를 manual로 넘겨줌.
        break;                              // 조건이 return이 0이 아니면 끝.
    }
    return sum;                         // r4를 return함.
}

출처 : http://recipes.egloos.com/5027277
















디렉티브

1) Export  i  (== 전역변수)
    -> 즉, i 라는 변수를 현재의 파일내에서 최초 선언하여 사용했지만, 다른 Object 파일에서 참조한다는 것을
        assembler에게 알려주는 것.

2) IMPORT i (== extern int i;)
    -> 현재의 소스파일에서 사용되는 변수 i는 다른 Object 파일에서 선언되어져 있다는 것을
        Assembler 에게 알려주는 것입니다.


3) DCD == " = "
    -> 즉 "table DCD 1,2,4 " 라고 되어진 것은 32bit 로 메모리를 3개 할당하고
        각각에 1,2,4 라는 값을 초기값으로 넣고 그 시작 Address는 table 이라는 label 로 표현되어 집니다.
        이것을 C로 표현하면 unsigned int table[3] = {1,2,4};

4) AREA == segment
    -> 모든 프로그램은 크게 두가지의 기계어 영역을 반드시 포함하고 있습니다.
    -> 실제로 실행하여야할 실행 코드를 포함하는 영역, 실행코드를 수행하기 위하여 사용되는 변수를
         정의하여 R/W 하는데 사용해야할 영역, 전자는 CODE area 와 후자는 DATA area 를 말하는 것입니다.



--------------------------------------------아직 정리 안함-------------------------------------------------------

5) ALIGN
-> ARM 은 기본적으로 모든 명령이 4byte 로 구성되어 집니다. 즉 4의 배수로 실행코드를 쪼개의 기계어를 하나하나 해석해 낸다고 보면 됩니다. 그런데 ASM 코드들 중간에 address 나 변수등을 정의할 때 1byte 나 2byte 로 정의를 해버리면 4의 배수가 않되는 경우가 발생합니다. 이때 오류가 발생할 수도 있습니다. 즉 4의 배수를 맞추기위하여 0으로 초기화되는 byte들을 추가로 패딩해주는 것이 필요한데 이것을 해주는 directive입니다.

6)SPACE
-> 초기값을 zero 로 지정한 바이트 만큼 메모리를 잡으라는 것입니다.

------------------------------------------------
EXPORT INT_Loaded_Flag
INT_Loaded_Flag DCD 0

-> INT_Loaded_Flag 라는 변수를 0으로 잡는데 그 크기는 4bytes로 한다. 그리고 이 변수는 다른 파일에서 참조되어진다.
------------------------------------------------
IMPORT INT_Initialize
INT_Resel_Addr DCD INT_Initialize

-> INT_Initialize 라는 이름의 함수 또는 변수가 현재의 파일이외에 다른 파일에 선언되어져 있는데 이것을 현재의 파일에서 참조하고 그 Address를 4bytes 크기로 끈어서 INT_Resel_Addr라는 변수명으로 재 정의한다.
------------------------------------------------
INT_IRQ_Vectors
DCD INT_IRQ_Shell

-> INT_IRQ_Shell 이라는 함수의 시작 Address를 INT_IRQ_Vectors라는 사람이 인지할 수있는 label 로 재정의 한다.
-----------------------------------------------
INT_bss_start
DCD |Image$$bss$$Base|

-> 이것은 "Image$$bss$$Base"의 의미를 알아야 합니다. Image$$bss$$Base은 ARM assembler/linker 가 이해하는 label 입니다. 이것은 이미 무언의 약속으로 정의된 label 이므로 프로그래머가 어셈 코드에서 따러 정의하지 않아도 ARM asembler/compiler 가 알아서 생성해내는label 입니다. Image$$bss$$Base의 의미만 말하면 , bss 영역의 시작 address를 의미하는 것입니다.
즉, bss 영역의 시작 address를 INT_bss_start
라는 label로 재정의하여 프로그램을 용이하게 하겠다는 directive문구 입니다.

출처 : http://gauss.egloos.com/643866

2011/02/22 15:27 2011/02/22 15:27

이 글에는 트랙백을 보낼 수 없습니다