libc.so는 표준 C라이브러리를 모듈화 한 파일이다. 솔라리스에서 C 컴파일러로 컴파일 되었다면, 정적으로 컴파일하지 않는한 libc.so파일을 로드하게 된다. [# ldd /usr/bin/ls]를 해보면 가장 기본적인 명령어인 ls조차도 libc.so를 읽도록 되어있는것을 알 수 있다. 간단히 말해 솔라리스에서 작동하는 모든 프로그램은 libc.so를 사용하고 있다고 해도 과언은 아니다. (솔라리스 10의 초기에는 /sbin 아래의 파일들은 libc.so를 사용하지 않았지만 지금은 사용한다)
솔라리스 11에는 3가지의 libc.so 파일이 있다. /lib/libc.so.1, /usr/lib/libc/libc_hwcap1.so.1, /usr/lib/libc/libc_hwcap2.so.1, /usr/lib/libc/libc_hwcap3.so.1 이 그것. 같은 라이브러리를 3개나 만든건 최신 CPU의 명령셋을 지원해 성능을 향상시킬 목적으로 만든것이다. (hwcap은 HardWare CAPabilities의 약어이다)
주) 아래의 내용 중 umount 명령 부분은 [테스트용 시스템]에서 하는 것이 좋다.
root@wl ~ # df -h
...
/usr/lib/libc/libc_hwcap1.so.1
623G 9.5G 613G 2% /lib/libc.so.1
...
root@wl ~ # umount /lib/libc.so.1
root@wl ~ # file /lib/amd64/libc.so.1 /lib/libc.so.1 /usr/lib/libc/libc_*
/lib/amd64/libc.so.1: ELF 64-bit LSB dynamic lib AMD64 Version 1
[SSE2 SSE CMOV FPU], dynamically linked, not stripped, no debugging information available
/lib/libc.so.1: ELF 32-bit LSB dynamic lib 80386 Version 1
[SSE MMX CMOV SEP CX8 FPU], dynamically linked, not stripped, no debugging information available
/usr/lib/libc/libc_hwcap1.so.1: ELF 32-bit LSB dynamic lib 80386 Version 1
[SSE MMX CMOV SEP CX8 FPU], dynamically linked, not stripped, no debugging information available
/usr/lib/libc/libc_hwcap2.so.1: ELF 32-bit LSB dynamic lib 80386 Version 1
[SSE2 SSE MMX CMOV AMD_SYSC CX8 FPU], dynamically linked, not stripped, no debugging information available
/usr/lib/libc/libc_hwcap3.so.1: ELF 32-bit LSB dynamic lib 80386 Version 1
[SSE MMX CMOV CX8 FPU], dynamically linked, not stripped, no debugging information available
root@wl ~ # isainfo -v
64-bit amd64 applications
avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2
sse fxsr mmx cmov amd_sysc cx8 tsc fpu
32-bit i386 applications
avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2
sse fxsr mmx cmov sep cx8 tsc fpu
root@wl ~ # cat /usr/include/sys/auxv_386.h
...
#define AV_386_PAUSE 0x02000 /* use pause insn (in spin loops) */ // 없어짐
...
#define AV_386_MON 0x08000 /* monitor/mwait insns */ // 없어짐
...
#define AV_386_AHF 0x20000 /* lahf/sahf insns */
...
#define AV_386_MOVBE 0x2000000 /* Intel MOVBE insns */
...
#define AV_386_AVX 0x20000000 /* Intel AVX insns */
...
root@wl ~ #
wl시스템은 [avx xsave pclmulqdq aes sse4.2 sse4.1 ssse3 popcnt tscp cx16 sse3 sse2 sse fxsr mmx cmov amd_sysc cx8 tsc fpu] 을 지원하고 이에 맞춰서 /usr/lib/libc/libc_hwcap1.so.1 가 선택되었다.
CMOV
CMOV: conditional move 라는 어셈블리 명령이다.
CMP EAX, EBX
JBE skip
MOV EAX, EBX
skip:
→
CMP EAX, EBX
CMOVA EAX, EBX
CMOVA 는 conditional move if above 라는 뜻의 명령어이다. 위 예제는 EAX와 EBX중 작은 것을 취하는 내용이다. 펜티엄 프로부터 추가되었다.
SEP,AMD_SYSC
※ SEP
Intel CPU에는 SYSENTER,SYSEXIT 명령셋(어셈블리언어 명령어)이 추가되어있다. 이 명령셋은 Fast System Call(SEP)라 부르며 인텔 펜티엄 프로 이상에서 사용 가능하다. (Fast System Call을 사용하기 위해서는 SEP(SYSENTER Present)비트가 반드시 셋 되어있어야 한다)
※ AMD_SYSC
AMD System Call 의 약어. AMD사가 SYSCALL,SYSRET 명령셋으로 Intel의 SYSENTER, SYSEXIT과 동일한 역할을 한다.
※ 쉽게 말해 빠른 시스템콜 호출을 위해 CPU제조사는 독자적인 명령셋을 개발했고 그것이 Intel CPU에서는 SEP, AMD CPU에서는 AMD_SYSC이다. 그리고 솔라리스10 에서는 이를 감지해 사용한다.
FXSR
FXSAVE 와 FXRSTOR (Fast FPU/SIMD state Save/Restore)명령구문을 의미한다. OS와 CPU에서 동시에 지원하면 컨텍스트 스위칭을 빠르게 수행한다. 이 명령셋을 사용하려면 SSE를 지원하는 CPU가 필요하다.
CX16, CX8
cmpxchg16b(Compare and Exchange 16 Bytes)명령구문을 의미한다. CX8(cmpxchg8b)명령의 16 바이트 버전이다. 초기의 AMD 64 CPU에서는 오류가 있다. 128비트 부동 소수점 연산시 컨텍스트 스위칭에 대비해 '락'을 걸게 되는데, 이 명령은 LOCK 접두어와 같이 사용해 원자단위 연산(atomic operation)이 가능하도록 하여 (수행 도중 컨텍스트 스위칭 할 수 없음) 결과적으로는 락 없이 연산 가능하도록 한다. 64bit CPU가 필요하다.
AHF
LAHF(Load Status Flags into AH), SAHF(Store AH into Flags) 명령어다. 기본적인 산술 플래그(SF, ZF, AF, PF, CF )를 AH에 저장하거나 AH에서 로드한다. 인텔의 초기 64bit 프로세서에서 오류가 있었기도 하다.
TSCP, TSC
RDTSCP(Read Time-Stamp Counter and Processor ID), RDTSC(Read Time-Stamp Counter)명령이다. 전자는 64비트 타임스탬프와 32비트 IA32_TSC_AUX 값을 EDX:EAX, ECX에 넣는다. 후자는 프로세스 아이디를 로드하지 않는다.
POPCNT
POPCNT(Population count)명령이다. 2진 표현에서 1의 개수를 세는 명령이다.
LZCNT
LZCNT(Leading zero count)명령이다. 2진 표현에서 앞에 0이 몇개인지 세는 명령이다. AMD CPU에서만 지원된다.
MOVBE
MOVBE(Move Data After Swapping Bytes)명령이다.
PCLMULQDQ
PCLMULQDQ(Performs a carry-less multiplication of two 64-bit integers)명령이다. AES GCM계산할 때 사용된다.
root@wl ~ # df -k
/usr/lib/libc/libc_hwcap1.so.1
50423874 7450881 42468755 15% /lib/libc.so.1
root@wl ~ # ls -al /usr/lib/libc/libc_hwcap1.so.1 /lib/libc.so.1 1)
-rwxr-xr-x 1 root bin 1087992 9월 18일 02:00 /lib/libc.so.1
-rwxr-xr-x 1 root bin 1087992 9월 18일 02:00 /usr/lib/libc/libc_hwcap1.so.1
root@wl ~ # digest -a md5 /usr/lib/libc/libc_hwcap1.so.1
30fc278a5f38f9141be68b1d83ae70f0
root@wl ~ # digest -a md5 /lib/libc.so.1
30fc278a5f38f9141be68b1d83ae70f0
root@wl ~ # umount /lib/libc.so.1 2)
root@wl ~ # ls -al /usr/lib/libc/libc_hwcap1.so.1 /lib/libc.so.1 3)
-rwxr-xr-x 1 root bin 1083760 9월 18일 01:59 /lib/libc.so.1
-rwxr-xr-x 1 root bin 1087992 9월 18일 02:00 /usr/lib/libc/libc_hwcap1.so.1
root@wl ~ # mount -O -F lofs /usr/lib/libc/libc_hwcap1.so.1 /lib/libc.so.1 4)
1) 두 파일이 같은 파일임을 알 수 있다. 시스템에 따라 /usr/lib/libc/libc_hwcap2.so.1 와 연결되어있을 수 있다. 그렇다면 이 예제에서는 파라메터를 바꿔서 시험해봐야 한다. 2) 마운트를 해제한다. 3) 두 파일이 다른 파일임을 알 수 있다. 파일 용량부터 차이난다. 원래 있는 파일을 지우지 않기 위해 lofs를 이용해 마운트한 것이다. 4) 다시 원래대로 복구한다.
※ lofs로 마운트 해서 마운트 한것 처럼 보이지만, 실제로는 그냥 파일이다.
root@wl ~/src # cc -g -o libc_0 libc_0.c
root@wl ~/src # ./libc_0
세그멘테이션 결함(Segmentation Fault) (core dumped)
139 root@wl ~/src # dbx libc_0 core
For information about new features see `help changes'
To remove this message, put `dbxenv suppress_startup_message 7.9' in your .dbxrc
Reading libc_0
core file header read successfully
Reading ld.so.1
Reading libc.so.1
program terminated by signal SEGV (no mapping at the fault address)
0xfee663dc: strlen+0x000c: movl (%eax),%edx
Current function is main
12 printf("NULL String: %s\n", str);
(dbx) examine str
0x00000000: dbx: core file read error: address 0 not in data space
(dbx) exit
소스를 수정하는 것이 가장 좋지만, 여의치 않을 경우 0@0.so.1 을 미리 로드 시켜 실행시켜 주면 된다. 하지만 이렇게 하면 몇가지 솔라리스 툴을 사용하는데 있어 제약이 따른다. 예를 들어 truss를 실행시킬 수 없다.