OldPapers/linux
[ARM] Veneer code
꿈꾸는네오
2007. 11. 16. 14:23
Veneer에 대한 정의 입니다.
Veneer : armlinker가 생성하는 veneers 에 대한 세부 정보
Linker는 ARM 코드와 Thumb 코드를 link 할 수 있고, 필요 시 자동적으로
processor state를 변경 하기 위한 interworking veneer를 생성하고, 필요한 곳
에 branch instruction의 range를 확장하기 위해 long branch veneers를 생성한다
Arm linker는 Arm function이 Thumb state에 호출되거나 Thumb function이 Arm
state에서 호출되는 것 을 detect할 수 있고, 필요 시 processor state를 변경하
기 위해 call과 return instruction을 변경 하거나 veneers라고 불리는 작은 code
section을 삽입한다.
위에 정의된 내용만으로는 뭐하는건지 잘 모르겠죠.. 간단한 예를 들어보겠습니다.
다음과 같은 arm모드로 컴파일이된 arm.s 라는 소스가 있고 thumb 모드로 컴파일된 thumb.s 라는 소스가 있다고 하죠
둘다 컴파일 옵션에는 interwork 를 줘야 같이 동작할 수 가 있습니다.
; ******
; arm.s
; ******
AREA Arm,CODE,READONLY
IMPORT ThumbProg
ENTRY
ARMProg
MOV r0,#1
BL ThumbProg
MOV r2,#3
MOV r0, #0x18
LDR r1, =0x20026
SWI 0x123456
END
; *******
; thumb.s
; ********
AREA Thumb,CODE,READONLY
CODE16
EXPORT ThumbProg
ThumbProg
MOV r1, #2
BX lr
END
위의 소스를 보면 arm모드로 컴파일되는 arm.s와 thumb모드로 컴파일되는 thumb.s 소스가 있습니다.
일반적으로 arm모드에서 thumb 모드의 코드로 branch하거나 thumb모드에서 arm모드로 branch할때는 BX 명령어가 사용됩니다.
하지만 arm.s 에서 보면 BL ThumProg 로 Thumb코드인 ThumbProg 함수를 BL 로 호출 했습니다.
이럴 경우 링커는 자동으로 해당 부분에 Veneer 코드를 삽입하여 arm 모드에서 thumb모드로 변환할 수 있는 코드를 넣게 됩니다.
이런 코드를 Veneer 코드라고 하며 위의 소스를 컴파일 한후 disassemble한 코드로 살펴 보면 아래와 같습니다.
armsd: list 0x8000
ARMProg
0x00008000: 0xe3a00001 .... : > mov r0,#1
0x00008004: 0xeb000005 .... : bl $Ven$AT$$ThumbProg
0x00008008: 0xe3a02003 . .. : mov r2,#3
0x0000800c: 0xe3a00018 .... : mov r0,#0x18
0x00008010: 0xe59f1000 .... : ldr r1,0x00008018 ; =#0x00020026
0x00008014: 0xef123456 V4.. : swi 0x123456
0x00008018: 0x00020026 &... : dcd 0x00020026 &...
ThumbProg
+0000 0x0000801c: 0x2102 .! : mov r1,#2
+0002 0x0000801e: 0x4770 pG : bx r14
$Ven$AT$$ThumbProg
+0000 0x00008020: 0xe59fc000 .... : ldr r12,0x00008028 ; = #0x0000801d
+0004 0x00008024: 0xe12fff1c ../. : bx r12
+0008 0x00008028: 0x0000801d .... : dcd 0x0000801d ....
+000c 0x0000802c: 0xe800e800 .... : dcd 0xe800e800
+0010 0x00008030: 0xe7ff0010 .... : dcd 0xe7ff0010 ....
+0014 0x00008034: 0xe800e800 .... : dcd 0xe800e800 ....
+0018 0x00008038: 0xe7ff0010 .... : dcd 0xe7ff0010 ....
disassemble된 코드를 살펴 보면 이전 bl ThumbProg 가 있던 자리에 bl $Ven$AT$$ThumbProg 로 바뀐것을 볼 수 있습니다.
이 코드가 바로 veneer 코드 이며 arm 모드에서 thumb 모드로 컴파일된 함수를 호출 하기 위해 BX 를 사용하도록 linker가
바꾼 것입니다.
실제 아래쪽에 보면 $Ven$AT$$ThumbProg 로 Lable 이 붙은 코드가 추가가 되었습니다.
BL $Ven$AT$$ThumbProg 에 의해 $Ven$AT$$ThumbProg 로 가보면 이곳에서 하는일은 처음에
r12에다 0x00008028 번지에 있는 값인 0x0000801d 를 넣습니다.
그다음이 bx r12 를 하게 되는데 결국 사용자가 bl ThumbProg로 코드를 작성했지만 thumb모드로 바꾸기위해 링커가
bx 0x0000801d 라는 코드로 바꾼것입니다. (BX를 쓰게되면 해당번지로 branch한 후 state를 바꾸게 됩니다. 번지가 홀 수 번지이면 arm모드에서 thumb 모드로 번지가 짝수 번지이면 thumb모드에서 arm 모드로 state를 바꾸게 됩니다.)
결국 bx 0x0000801d 는 홀수 번지 branch이므로 0x0000801c 번지로 branch하고 arm에서 thumb으로 state를 바꿉니다.
그럼 0x0000801c 번지에는 기존의 ThumbProg 코드가 있습니다. 여기서 해당 코드 수행을 하고 다시 bx r14에 의해 (r14에는 bl 를 한다음 돌아갈 주소가 짝수번지로 들어가 있음 0x00008008) 다시 0x00008008 번지로 branch하고 번지가 짝수 이므로 thumb에서 arm으로 state를 바꾸게 됩니다.
이렇게 사용자가 arm/thumb interworking을 고려하지 않고 코드를 짜더라도 링커가 자동으로 해석해서 해당 모드를 바꿀 수 있게 코드를 삽입하게 되는데 이런 코드를 veneer 코드라고 합니다.
arm/thumb interworking 뿐아니라 long jump를 할경우도 이런 veneer 코드가 생기는 arm 모드에서 최대 32M 영역까지 branch를 할 수 있고 thumb 모드에서는 최대 4M 영역까지 branch를 할 수 있습니다. 마찬가지로 thumb모드에서 4M를 넘어가는곳의 함수를 호출 하는경우 링커는 알아서 veneer 코드를 만들어 arm 모드로 state를 바꾸고 해당 영역으로 branch한 후 다시 thumb 모드로 바꿔주는 코드를 삽입하게 됩니다.
$Ven$AT$$ThumbProg 여기서 $Ven 은 veneer 코드라는 의미이고 $AT 는 Arm 모드에서 Thumb 모드로 변경한다는 의미입니다.