오늘은 thumb-2 code 가 절 고민하게 만들었습니다.
아시다 시피 ARM 은 기본적으로 두가지 모드(arm code , thumb code) 를 지원합니다.
arm 은 32bit instruction 이고 thumb 는 16 bit instruction 이지요.
헌데 thumb-2 와 thumbEE 라는 32 bit instruction 이 나와서 instruction 의 길이만으로 구별하기가 참 애매해 졌습니다.
단순하게 thumb 만으로만 build 된 경우 objdump 로 build 된 영역을 interpret 해 보면 thumb 인지 금방 알 수 있습니다.
instruction 이 16bit 로 나오거든요..
thumb mode 로 빌드하려면 컴파일 시 다음 옵션을 추가하면 됩니다.
-mthumb -mthumb-interwork
< thumb code 로 컴파일된 binary >
< arm code 로 컨파일된 binary >
동일한 C 코드를 옵션만 바꾸어서 빌드한 경우입니다.
하지만 thumb-2 의 경우는 이렇게 판단하기가 쉽지 않습니다.
구글링을 한참 하다가 아래 링키에서 해답을 찾을 수 있었습니다.
https://wiki.ubuntu.com/ARM/Thumb2PortingHowto
풀이해서 말하자면
thumb-2 로 컴파일 된 녀석은 buttom bit 가 set 되어 있다고 합니다. 한마디로 홀수 주소를 가지는 거지요.
하지만 objdump 로 interpret 을 하면 buttom bit 를 빼고 읽는 다고 합니다.
위에 NenoTest 함수가 Thumb code 로 빌드되었는데도 불구하고 짝수 주소를 가지는 이유 입니다.
readelf 로 symbol 정보를 보면 thumb 로 빌드한 경우 홀수 주소를 가지는 것을 볼 수 있습니다.
> arm-none-linux-gnueabi-readelf -s buildtest-thumbR
95: 000105d8 0 NOTYPE GLOBAL DEFAULT ABS _bss_end__
96: 000105d8 0 NOTYPE GLOBAL DEFAULT ABS _end
97: 00008379 132 FUNC GLOBAL DEFAULT 12 NeonTest
98: 000105d4 0 NOTYPE GLOBAL DEFAULT ABS _edata
99: 000084a8 0 NOTYPE GLOBAL DEFAULT ABS __exidx_start
100: 000083fd 50 FUNC GLOBAL DEFAULT 12 main
101: 0000828c 0 FUNC GLOBAL DEFAULT 10 _init
직접 compile 한 NeonTest 와 main 함수가 홀수 주소를 가지는 것을 볼 수 있습니다.
다만 thumb-2 code 의 경우 32bit arm code 와 혼용해서 사용하게 되는데
이 방법으로는 symbol 로 매칭이 되어있을 경우만 판단이 가능합니다.
arm code 사이에 끼어있는 thumb-2 code 는 구별할 수 없는것이지요.
그 방법에 대해서는 알게 되는데로 posting 하도록 하겠습니다.
- thumb instruction quick reference card
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006d/QRC0006_UAL16.pdf
- thumb-2 instruction quick reference card
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf
- arm instruction quick reference card
http://www.simplemachines.it/doc/QRC0001H_rvct_v2.1_arm.pdf
또 하나 재미있는것..
다음과 같이 파일을 하나 만듭니다.
> cat tt
.aaa:
mov r1, r2
목적파일을 만듭니다.
arm-none-linux-gnueabi-as tt -o aa.out
이것을 objdump 로 보면 다음과 같습니다.
arm-none-linux-gnueabi-objdump -d aa.out
aa.out: file format elf32-littlearm
Disassembly of section .text:
00000000 <.aaa>:
0: e1a01002 mov r1, r2
다시 -mthumb -mthumb-interwork 옵션으로 컴파일 합니다.
arm-none-linux-gnueabi-as tt -o aa.out -mthumb -mthumb-interwork
이것을 objdump 로 보면 compile 가 mov 에 대응하는 adds 의 thumb 로 변환해서 compile 한것을 볼 수 있습니다.
arm-none-linux-gnueabi-objdump -d aa.out
aa.out: file format elf32-littlearm
Disassembly of section .text:
00000000 <.aaa>:
0: 1c11 adds r1, r2, #0
추가로 readelf 로 읽을때 다음과 같이 출력되는데 $t 는 thumb를 $a 는 arm code 를 의미합니다.
arm-none-linux-gnueabi-readelf -s aa.out
아시다 시피 ARM 은 기본적으로 두가지 모드(arm code , thumb code) 를 지원합니다.
arm 은 32bit instruction 이고 thumb 는 16 bit instruction 이지요.
헌데 thumb-2 와 thumbEE 라는 32 bit instruction 이 나와서 instruction 의 길이만으로 구별하기가 참 애매해 졌습니다.
단순하게 thumb 만으로만 build 된 경우 objdump 로 build 된 영역을 interpret 해 보면 thumb 인지 금방 알 수 있습니다.
instruction 이 16bit 로 나오거든요..
thumb mode 로 빌드하려면 컴파일 시 다음 옵션을 추가하면 됩니다.
-mthumb -mthumb-interwork
< thumb code 로 컴파일된 binary >
00008378 <NeonTest>:
8378: b580 push {r7, lr}
837a: b086 sub sp, #24
837c: af00 add r7, sp, #0
837e: 1c3b adds r3, r7, #0
8380: 330c adds r3, #12
8382: 6018 str r0, [r3, #0]
8384: 1c3b adds r3, r7, #0
8378: b580 push {r7, lr}
837a: b086 sub sp, #24
837c: af00 add r7, sp, #0
837e: 1c3b adds r3, r7, #0
8380: 330c adds r3, #12
8382: 6018 str r0, [r3, #0]
8384: 1c3b adds r3, r7, #0
< arm code 로 컨파일된 binary >
00008378 <NeonTest>:
8378: e52db004 push {fp} ; (str fp, [sp, #-4]!)
837c: e28db000 add fp, sp, #0 ; 0x0
8380: e24dd01c sub sp, sp, #28 ; 0x1c
8384: e50b0010 str r0, [fp, #-16]
8388: e50b1014 str r1, [fp, #-20]
838c: e50b2018 str r2, [fp, #-24]
8390: e3a03000 mov r3, #0 ; 0x0
8394: e50b3008 str r3, [fp, #-8]
8398: ea000016 b 83f8 <NeonTest+0x80>
8378: e52db004 push {fp} ; (str fp, [sp, #-4]!)
837c: e28db000 add fp, sp, #0 ; 0x0
8380: e24dd01c sub sp, sp, #28 ; 0x1c
8384: e50b0010 str r0, [fp, #-16]
8388: e50b1014 str r1, [fp, #-20]
838c: e50b2018 str r2, [fp, #-24]
8390: e3a03000 mov r3, #0 ; 0x0
8394: e50b3008 str r3, [fp, #-8]
8398: ea000016 b 83f8 <NeonTest+0x80>
동일한 C 코드를 옵션만 바꾸어서 빌드한 경우입니다.
하지만 thumb-2 의 경우는 이렇게 판단하기가 쉽지 않습니다.
구글링을 한참 하다가 아래 링키에서 해답을 찾을 수 있었습니다.
https://wiki.ubuntu.com/ARM/Thumb2PortingHowto
풀이해서 말하자면
thumb-2 로 컴파일 된 녀석은 buttom bit 가 set 되어 있다고 합니다. 한마디로 홀수 주소를 가지는 거지요.
하지만 objdump 로 interpret 을 하면 buttom bit 를 빼고 읽는 다고 합니다.
위에 NenoTest 함수가 Thumb code 로 빌드되었는데도 불구하고 짝수 주소를 가지는 이유 입니다.
readelf 로 symbol 정보를 보면 thumb 로 빌드한 경우 홀수 주소를 가지는 것을 볼 수 있습니다.
> arm-none-linux-gnueabi-readelf -s buildtest-thumbR
95: 000105d8 0 NOTYPE GLOBAL DEFAULT ABS _bss_end__
96: 000105d8 0 NOTYPE GLOBAL DEFAULT ABS _end
97: 00008379 132 FUNC GLOBAL DEFAULT 12 NeonTest
98: 000105d4 0 NOTYPE GLOBAL DEFAULT ABS _edata
99: 000084a8 0 NOTYPE GLOBAL DEFAULT ABS __exidx_start
100: 000083fd 50 FUNC GLOBAL DEFAULT 12 main
101: 0000828c 0 FUNC GLOBAL DEFAULT 10 _init
직접 compile 한 NeonTest 와 main 함수가 홀수 주소를 가지는 것을 볼 수 있습니다.
다만 thumb-2 code 의 경우 32bit arm code 와 혼용해서 사용하게 되는데
이 방법으로는 symbol 로 매칭이 되어있을 경우만 판단이 가능합니다.
arm code 사이에 끼어있는 thumb-2 code 는 구별할 수 없는것이지요.
그 방법에 대해서는 알게 되는데로 posting 하도록 하겠습니다.
- thumb instruction quick reference card
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006d/QRC0006_UAL16.pdf
- thumb-2 instruction quick reference card
http://infocenter.arm.com/help/topic/com.arm.doc.qrc0001l/QRC0001_UAL.pdf
- arm instruction quick reference card
http://www.simplemachines.it/doc/QRC0001H_rvct_v2.1_arm.pdf
또 하나 재미있는것..
다음과 같이 파일을 하나 만듭니다.
> cat tt
.aaa:
mov r1, r2
목적파일을 만듭니다.
arm-none-linux-gnueabi-as tt -o aa.out
이것을 objdump 로 보면 다음과 같습니다.
arm-none-linux-gnueabi-objdump -d aa.out
aa.out: file format elf32-littlearm
Disassembly of section .text:
00000000 <.aaa>:
0: e1a01002 mov r1, r2
다시 -mthumb -mthumb-interwork 옵션으로 컴파일 합니다.
arm-none-linux-gnueabi-as tt -o aa.out -mthumb -mthumb-interwork
이것을 objdump 로 보면 compile 가 mov 에 대응하는 adds 의 thumb 로 변환해서 compile 한것을 볼 수 있습니다.
arm-none-linux-gnueabi-objdump -d aa.out
aa.out: file format elf32-littlearm
Disassembly of section .text:
00000000 <.aaa>:
0: 1c11 adds r1, r2, #0
추가로 readelf 로 읽을때 다음과 같이 출력되는데 $t 는 thumb를 $a 는 arm code 를 의미합니다.
arm-none-linux-gnueabi-readelf -s aa.out
Symbol table '.symtab' contains 7 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 1 .aaa
5: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
6: 00000000 0 SECTION LOCAL DEFAULT 4
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 1 .aaa
5: 00000000 0 NOTYPE LOCAL DEFAULT 1 $t
6: 00000000 0 SECTION LOCAL DEFAULT 4
'Programming > ARM' 카테고리의 다른 글
ARM 의 TLB 운용에 대한 간단 정리 (0) | 2014.05.20 |
---|---|
눈으로 보는 ARM - ASM 해석 (0) | 2010.09.22 |
Cache - Flush, clean, Invalidate (0) | 2010.06.24 |
L1, L2 cache 와 I cache, D cache 의 관계 (2) | 2010.05.04 |
arm - SIGSERV나 SIGILL 이 발생했을때의 asm 동작 (0) | 2010.04.23 |