|
HWCAP 은 프로그램의 오브젝트 파일에 추가되는 비트들의 셋입니다. 이러한 비트들은 프로그램의 특정 하드웨어 사용가능성을 묘사 합니다. 이것은 썬 스튜디오10의 새로운 기능이고 썬 스튜디오11 혹은 그 이후 버젼에서도 지원 됩니다. 이 글의 모든 예제코드들은 AMD 혹은 인텔 64-비트 아키텍쳐를 위한 포트란 코드가 사용됩니다. HWCAP 기능은 또한 C/C++ 코드에서도 사용가능하고 모든 32/64-비트 SPARC, AMD 혹은 인텔 프로세서를 지원 합니다.
하드웨어-특수한 명령은 HWCAP 비트셋에 대응되는 형태로 프로그램 상에 포함됩니다.이의 예제로는 prefetch 명령어를 포함하는 프로그램을 들 수 있습니다. 몇가지 다른 prefetch 명령어가 존재 하지만 모든 프로세서가 지원하지는 않습니다. 컴파일러가 prefetch 같은 하드웨어-특수한 명령어를 찾아 내면 프로그램 오브젝트 파일의 일부분에 HWCAP 비트가 지정 됩니다. 후에 링크 과정에서 HWCAP 비트와 머신의 프로세서와 비교할 것이빈다. 만약 프로세서가 비트가 가르키고 있는 prefetch 명령어를 지원하지 않는 다면 링커는 종려 됩니다. 이러한 보호 장치는 지원되지 않는 명령어의 실행을 막아 줍니다.
그러나 몇몇 경우 프로그래머는 HWCAP의 보호장치를 오바라이드 하길 원할 수도 있습니다. 이에 대한 예로써 각 프로세서마다 다른 타입의 라이브러리를 생성하는 것을 들 수 있습니다. 만약 라이브러리가 이러한 서로 다른 프로세서에 특정한 명령어를 포함한다면 프로그래머는 두가지 일을 할 수 있습니다.
첫번째 옵션으로 각 프로세서의 특정한 라이브러리 안에 각 프로그램의 카피를 만드는 방법이 있습니다. 라이브러리는 반드시 공유 오브젝트의 형태(.so 파일)로 만들어져야 합니다. 공유 오브젝트를 링크 할때 올바른 버젼의 프로그램이 호출 됩니다. 이것은 대부분의 코드가 완전히 다를 경우 올바른 선택이 될 수 있습니다. 이러한 방법의 단점은 각 프로그램의 카피를 가짐으로써 유지보수가 어렵고 메모리의 공간을 많이 차지 할 수도 있습니다.
또 다른 옵션으로는 프로세서-특정한 명령어를 조건 표현문으로 구분하여 포함시키는 방법입니다. 실행시에는 적절한 코드가 실행 됩니다. 이것은 프로그램이 적절한 코드 명령어를 사용하기 위해 하드웨어 사용 가능성을 체크해야 하는 것을 요구합니다. 이것은 대부분의 코드가 동일 할때 장점을 가질 수 있습니다. 이 두번째 옵션은 HWCAP 비트들의 변경을 요구 합니다. 프로그램이 고유의 하드웨어 검사를 하더라도 링커는 종료될 것입니다. 이것을 회피하기 위해 링커는 모든 코드가 안전하다고 착각해야 합니다. 이 것은 프로그래머가 하드웨어 사용가능성을 올바르게 체크 한다는 책임을 가지고 있어야 하고 적절한 코드 명령어를 실행 해야 합니다. 만약 실패 한다면 예측 불가능한 행동을 유발할 것입니다. 프로그램이 코어 덤프 되거나 예측불가능하게 종료 되거나 올바르지 않은 결과를 생성할 것입니다.
HWCAP 비트는 이름 혹은 16진수 값의 두가지 방법으로 표현 될 수 있습니다. 이 비트는 커맨드라인 유틸리티 file (예제1 참조) 혹은 elfdump (예제 2 참조)를 이용하여 확인할 수 있습니다..
예제 1: file 커맨드 사용하기
> file dtest.o dtest.o: ELF 64-bit LSB relocatable AMD64 Version 1 [SSE2 AMD_3DNow] |
두가지 예제 모두 오브젝트 파일 dtest.o 에 SSE2 와 3DNow 라는 두가지 HWCAP 이름을 포함하고 있습니다. SSE2 는 대부분의 새로운 AMD 혹은 인텔 x86칩에 내장되어 있는 기능입니다. 3DNow는 AMD x86 칩에 포함되어 있습니다.
예제 2: elfdump 커맨드 사용하기
> elfdump -H dtest.o
Hardware/Software Capabilities Section: .SUNW_cap
index tag value
[0] CA_SUNW_HW_1 0x1100 [ SSE2 AMD_3DNow ]
|
예제 2에서, elfdump 커맨드를 사용하여, 추가 정보인 16진수 값 (0x1100) 을 얻었습니다. 비록 이러한 예제가 x86 프로세서에 촛점을 마주고 있지만 SPARC 프로세서도 동일하게 수행될 수 있습니다. x86 플랫폼을 위한 전체 이름, 값의 리스트는 /usr/include/sys/auxv_386.h 파일에서 얻으실 수 있습니다:List 1 참고. SPARC 플랫폼은 sys/auxv_SPARC.h 파일을 참고 바랍니다. 예제2의 elfdump의 결과는 0x1100 이었습니다. 이것은 3DNow (0x00100) 와 SSE2 (0x01000)를 OR 연산한 값입니다.
List 1: x86 플랫폼을 위한 HWCAP 비트
#define AV_386_FPU 0x00001 /* x87-style floating point */ #define AV_386_TSC 0x00002 /* rdtsc insn */ #define AV_386_CX8 0x00004 /* cmpxchg8b insn */ #define AV_386_SEP 0x00008 /* sysenter and sysexit */ #define AV_386_AMD_SYSC 0x00010 /* AMD's syscall and sysret */ #define AV_386_CMOV 0x00020 /* conditional move insns */ #define AV_386_MMX 0x00040 /* MMX insns */ #define AV_386_AMD_MMX 0x00080 /* AMD's MMX insns */ #define AV_386_AMD_3DNow 0x00100 /* AMD's 3Dnow! insns */ #define AV_386_AMD_3DNowx 0x00200 /* AMD's 3Dnow! extended insns */ #define AV_386_FXSR 0x00400 /* fxsave and fxrstor */ #define AV_386_SSE 0x00800 /* SSE insns and regs */ #define AV_386_SSE2 0x01000 /* SSE2 insns and regs */ #define AV_386_PAUSE 0x02000 /* use pause insn (in spin loops) */ #define AV_386_SSE3 0x04000 /* SSE3 insns and regs */ #define AV_386_MON 0x08000 /* monitor/mwait insns */ #define AV_386_CX16 0x10000 /* cmpxchg16b insn */ |
오브젝트파일 dtest.o 는 반드시 3DNow 와 SSE2 기능을 가지고 있는 머신에서 실행되어야 합니다. 링커는 반드시 이것을 확인해야 합니다. 두가지 방법 링커가 HWCAP 값을 체크하는 방법을 오버라이드 할 수 있습니다. 기억해야할 것은 HWCAP의 비트 값을 바꾸는 것이 프로그램에서의 해당 명령어를 제거하는 것은 아니란 것입니다. 이것은 비트의 특성을 단지 제거하여 링커가 머신의 하드웨어와 비교하는 것을 막을 뿐입니다. 대부분의 경우 프로그램은 지원되지 않는 명령을 구현하지 않도록 하기 위해 HWCAP 비트를 유지해야 합니다. HWCAP을 오버라이드 하는 것은 반드시 주의를 기울이고 반드시 필요할때만 수행해야 합니다.
이 예제에서는 3DNOW, SSE2 명령어를 포함하고 있는 루틴 dtest.f 를 사용합니다. dtest.f 가 수행되는 프로세서의 종류를 확인하고 AMD 혹은 인텔 플랫폼에 맞는 적절한 코드로 점프를 할수 있따고 가정해 봅시다. AMD 코드는 3DNOW 명령어를 포함하고 있습니다. 그러나 만약 프로그램이 인텔 프로세서-기반의 머신에서 컴파일된다면 링커는 종료될 것입니다. 왜냐하면 3DNow 명령이 지원되지 않기 ?문입니다. 링커는 코드의 어떠한 부분이 AMD를 위한 것이고 3DNow를 이용하는 루틴인지 모릅니다. 단순히 링커는 HWCAP 비트를 프로세서와 비교하여 이 경우는 종료되는 것입니다. 우리는 코드가 적절하게 프로세서를 체크하고 있음을 알기 ?문에 우리는 HWCAP을 오버라이딩 하여 트릭을 사용할 수 있습니다. 다시한번 말하자면 프로세서상에서 코드가 어떻게 동작하는지에 대한 지식이 있는 경우에만 사용해야 합니다. 지원되지 않는 인털 프로세서가 3DNow 명령어를 읽도록 하는 것은 좋은 생각이 아닙니다.
HWCAP 비트를 제거하기 위해 fbe (포트란 백엔드) 어셈블러의 옵션 -nH 가 사용됩니다. 이 작업을 하기 전에 루틴은 반드시 어셈블리로 변환되어야 합니다. 예제3을 참고 바랍니다. 첫번째 커맨드의 -S 옵션은 루틴 dtest.s 의 어셈블리 코드를 만드는 것입니다. 두번째 커맨드는 fbe 어셈블러를 이용해 dtest.s 를 컴파일 합니다. 그리고 옵션 -nH 는 HWCAP을 완전히 제거 합니다. 이것은 elfdump 의 공백 리턴값을 통해 확인되어질 수 있습니다. 그리고 file 커맨드를 이용해서도 확인할 수 있습니다. -nH 옵션은 두가지 단점이 존재 합니다. 첫번째는 모든 프로그램이 반드시 어셈블리로 변환된 다음 fbe 에섬블러에 의해 컴파일 되어야 한다는 것입니다. 이러한 두단계 과정은 번거로운 작업입니다. 이것은 시간이 더 걸리는 작업이고 그러므로 -nH 가 포트란 컴파일러에서 어셈블러로 직접적으로 넘겨질 수 있습니다. 두번째는 -nH 가 모든 HWCAP 정보를 제거한다는 것입니다.
예제 3: -nH 를 fbe 어셈블러와 같이 사용하기
> f90 -xarch=generic64 -S dtest.f > fbe -xarch=generic64 -nH dtest.s > elfdump -H dtest.o > file dtest.o dtest.o: ELF 64-bit LSB relocatable AMD64 Version 1 |
HWCAP 값을 제거 하는 또 다른 방법은 mapfile 을 이용하는 것입니다. 예제4에서 mapfile 에 모든 HWCAP 비트들을 제거 합니다. mapfile 사용하는 방법은 예제5에 나와 있습니다.
예제 4: Mapfile 을 이용하여 모든 HWCAP 비트 제거하기
> cat map.remove_all hwcap_1 = OVERRIDE |
맵파일은 방법2의 설명에서 자세히 설명됩니다. 3dNow만을 제거하고 SSE2를 남겨 두는 것은 좀 더 효율적인 방법이 될 것입니다. mapfile은 이러한 작업을 할 수도 있습니다.
예제 5: mapfile을 사용하는 링커
> f90 -xarch=generic64 -o temp.o -c dtest.f > ld -r -o dtest.o -Mmap.remove_all temp.o |
3DNow 비트 만을 제거 하기 위해 mapfile이 사용되어 질 수 있습니다. mapfile은 링커가 읽어들일 변경정보를 포함할 수 있습니다. mapfile 은 보통 다른 파일들과 구분하기 위해 map.my_name 의 형태로 명명되어 집니다. mapfile의 예제는 /usr/lib/ld 디렉토리에서 찾으실 수 있습니다. HWCAP을 위한 mapfile의 문법은 예제6에서 설명됩니다. 링커의 참고 문서에서 HWCAP 의 이름은 TOKEN 으로 불립니다. 일반적인 토큰의 이름은 AMD_3DNow, SSE, 그리고 SSE2 입니다. 이러한 이름들은 List 1 에서 prefix를 제외한 형태로 존재 합니다. 대신 값 (Vval) 이 사용될 수 있습니다: V0x00100, V0x00800, 그리고 V0x01000 (List 1 참조). 토큰은 논리 연산자인 OR을 이용해 결합됩니다. 이러한 방법으로 HWCAP에 비트값을 추가 시킵니다. 비트값을 제거하기 위해서는 워드 OVERRIDE 가 반드시 사용되어야 합니다. OVERRIDE 는 토큰이나 값을 mapfile 에서 가져와서 값 0으로 OR 연산을 수행합니다.
예제 6: HWCAP을 위한 mapfile 문법
hwcap_1 = TOKEN | Vval [OVERRIDE]; |
mapfile은 HWCAP의 비트값을 제거하고 추가할수 있다는 점에서 강력한 방법입니다. 예제7에서 볼수 있듯이 토큰 SSE는 는 mapfile을 생성함으로써 추가시킬 수 있습니다. 커멘트 아웃된 map.sse 는 Vval 값을 사용하는 대신에 쓸 수 있는 방법입니다. 토큰 이름이나 16진수 Vval 둘다 사용될 수 있습니다.
예제 7: HWCAP에 SSE 비트를 추가하기 위한 mapfile
> cat map.sse hwcap_1 = SSE; #hwcap_1 = V0x00800; // alternative form |
mapfile을 구현하기 위해서 링커 옵션 -M 을 사용하여 mapfile을 읽어 들이도록 합니다. 예제8은 HWCAP 값에 map.sse 를 사용하여 어떻게 SSE 값을 추가시키는지 보여 줍니다. 이것 또한 두단계의 과정임을 알 수 있습니다. 임시 오브젝트 temp.o 가 처음 생성되고 그다음에 로더에 전달되어 dtest.o 를 만들도록 합니다. 그러나 공유 오브젝트 라이브러리 (.so 파일) 이 생성되었다면 mapfile을 이용하는 링커의 과정은 오직 한번만 필요로 하게 되고 후에는 모든 루틴들이 공유 오브젝트 파일에 위치하게 됩니다.
예제 8: HWCAP에 SSE 비트 추가시키기
> f90 -xarch=generic64 -o temp.o -c dtest.f
> ld -r -o dtest.o -Mmap.sse temp.o
> file dtest.o
dtest.o: ELF 64-bit LSB relocatable AMD64 Version 1 [SSE2 SSE AMD_3DNow]
elfdump -H dtest.o
Hardware/Software Capabilities Section: .SUNW_cap
index tag value
[0] CA_SUNW_HW_1 0x1900 [ SSE2 SSE AMD_3DNow ]
|
예제 9 는 mapfile 을 이용하여 AMD_3DNow 값을 제거 하고 SSE 그리고 SSE2 비트 셋을 남겨 둡니다. 16진수 Vval 이 사용되었고 토큰 폼이 커멘트 아웃됐음을 알 수 있습니다. 또한 SSE 그리고 SSE2 를 제외한 다른 모든 비트들을 제거하기 위해 OVERRIDE 옵션이 사용 되었습니다. 3DNow 는 제거 되었습니다.
예제 9: SSE와 SSE2 만을 셋팅하기 위한 mapfile
> cat map.sse_sse2 #hwcap_1 = SSE SSE2 OVERRIDE; hwcap_1 = V0x00800 V0x01000 OVERRIDE; |
예제 10 은 링크 수행시에 HWCAP에서 AMD_3DNow 비트를 제거합니다. 또한 두가지 값인 SSE 와 SSE2 가 하나의 mapfile에서 사용되었음을 알 수 있습니다. HWCAP 값의 숫자 혹은 토큰은 이러한 방법으로 합쳐질 수 있고 이 것이 방법 2 를 좀더 안정적으로 만들어 줍니다.
예제 10: HWCAP에서 3DNow 비트를 제거하기
> f90 -xarch=generic64 -o temp.o -c dtest.f
> ld -r -o dtest.o -Mmap.sse_sse2 temp.o
> file dtest.o
dtest.o: ELF 64-bit LSB relocatable AMD64 Version 1 [SSE2 SSE]
> elfdump -H dtest.o
Hardware/Software Capabilities Section: .SUNW_cap
index tag value
[0] CA_SUNW_HW_1 0x1800 [ SSE2 SSE ]
|
결론적으로 HWCAP 비트를 수정하는 방법은 여러가지가 존재 합니다. 가장 빠르고 무식한 방법은 모든 비트를 제거하는 것입니다. 방법 2는 좀더 정확한 방법을 제공합니다. mapfile을 이용하여 HWCAP 에서 여러가지 비트를 동시에 추가 시키고 제거시킬 수 있습니다. 비록 이러한 예제가 포트란 프로그램으로 보여졌지만 썬 스튜디어 컴파일러를 통해 C와 C++에서도 동일한 과정을 할 수 있습니다. mapfile을 이용해 좀 더 많은 작업을 할 수 있지만 이것은 이 글의 범위를 벗어 납니다. HWCAP 비트를 수정 하는 것은 만약 코드가 명령어를 지원하지 않는 머신상에서 수행 되었을때 위험한 방법이 될 수 있습니다.
다른 자료는 Alfred Huang's blog 에서 찾으실 수 있습니다.
Sun Developer Network (SDN) 또한 최신 썬 컴파일러에 대한 글과 썬 엔지니어가 직접 답해주는 포럼을 제공함으로써 훌륭한 리소스가 될 수 있습니다. Sun Studio Compilers and Tools section 을 참고하시기 바랍니다.
"개발자코너" 카테고리의 다른 글
- DTrace를 사용하여 유저가 조정하는 애플리케이션 크래쉬 데이타 정보 모으기 (댓글 1개 / 트랙백 0개) 2006/08/23
- D 스크립트 배우기 (댓글 0개 / 트랙백 0개) 2009/11/23
- C++ 표준 라이브러리인 libCstd와 libstlport 비교하기 (댓글 1개 / 트랙백 0개) 2006/07/23
- 썬 스튜디오: VIS 명령을 사용하여 중요한 루틴의 속도를 향상시키기 (댓글 1개 / 트랙백 0개) 2006/02/23
- 썬 스튜디오 dbx 를 이용한 AMD64 명령어 레벨의 디버깅 (댓글 0개 / 트랙백 0개) 2007/12/14
- 솔라리스에서의 유저 인증: Part 1 (댓글 0개 / 트랙백 0개) 2007/10/21
- C++ ABI의 안정성: 프로그래밍 언어의 진화 (댓글 1개 / 트랙백 0개) 2006/02/23
- 솔라리스 디바이스 드라이버 작성을 원하십니까? (댓글 1개 / 트랙백 0개) 2008/09/18
- DLight 소개 (댓글 0개 / 트랙백 0개) 2009/06/29
- Dmalloc 을 솔라리스, 썬 스튜디오 컴파일러와 사용하기 (댓글 6개 / 트랙백 0개) 2007/06/13
댓글을 달아 주세요
좋은 정보 감사해요~
2007/09/19 04:14