カーネルをビルドする

■カーネルをビルドする (2010/01/06)

はじめに

 OSXはOSカーネルにBSDベースのカーネルを採用しており、10.5 LeopardからThe Open GroupよりSingle UNIX Specificationの認証を受けた正式なUNIX OS である。2009年末時点でThe Open Groupの認定を受け、UNIX商標を使えるOSは、Apple社のMac OS X 10.5 Leopard, 10.6 Snow Leopard、Sun Microsystems/富士通社のSolaris 10、HP社のHP-UX 11iv3、IBM社のAIX 5L、6の4製品のみである。Apple以外のOSは商用サーバ向けUNIX OSとして特殊なもの(シェア3割強でAIXがトップ)であり、実質的にUNIXのシェアトップはMac OS Xである。




 カーネルはオープンソースとして公開(各ベンダが知的所有権を有しソースを公開できないデバイスドライバなどはkext(カーネル拡張:kernel extension)としてバイナリのみのモジュールで提供されソースは非公開)されており、誰もが自由に閲覧し、使用することができる。

 Leopard 10.5についてはリファレンスライブラリのBuilding and Debugging Kernelsなどや、カーネルソースに付属するREADMEを参照することでビルドできるが、Snow Loepardからビルド方法が変更になった。その為、本項では一例として、2010年1月時点で最新の10.6.2のビルド方法を示す。

■1. 統合開発環境Xcode IDEを導入

1.1 Macデベロッパプログラムに加入

 Appleは、OSXでの統合開発環境(Xcode 3)を無償で提供しており、ADC(Apple Developer Connection)のOnline Membershipに登録することで誰でもダウンロードすることができる。


 なお、有料会員のADC Select Membership(US $499)もしくはADC Premier Membership(US $3499)に登録すると、Max OS Xの最新ビルドをダウンロードすることもできる。

1.2 Xcode for Mac-only Developmentからダウンロードし、インストール


 *Leopard(10.5)ではXcode 3.2.Xではなく、Xcode 3.1.Xをダウンロードする。

■2.ビルドツールのソースをダウンロード

2.1 ビルドに必要となるツールのソースをダウンロード


$ mkdir -p ~/Desktop/Dev
$ cd ~/Desktop/Dev
$ curl -s -O http://www.opensource.apple.com/tarballs/cxxfilt/cxxfilt-9.tar.gz
$ curl -s -O http://www.opensource.apple.com/tarballs/dtrace/dtrace-78.tar.gz
$ curl -s -O http://www.opensource.apple.com/tarballs/kext_tools/kext_tools-177.1.tar.gz
$ curl -s -O http://www.opensource.apple.com/tarballs/bootstrap_cmds/bootstrap_cmds-72.tar.gz

 *curlコマンドはwgetに相当するコマンドラインのファイルダウンロードツール

■3. ツールを解凍


$ tar zxf cxxfilt-9.tar.gz
$ tar zxf dtrace-78.tar.gz
$ tar zxf kext_tools-177.1.tar.gz
$ tar zxf bootstrap_cmds-72.tar.gz

■4.カーネルビルド用のツールをビルド

4.1 cxxfiltをビルドし、/usr/localにコピー


$ cd cxxfilt-9
$ mkdir -p obj sym dst
$ make install RC_ARCHS="i386 x86_64" RC_CFLAGS="-arch i386 -arch x86_64 -pipe" RC_OS=macos RC_RELEASE=SnowLeopard SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
$ sudo ditto $PWD/dst/usr/local /usr/local
Password:
$ cd ..

4.2 dtraceをビルドし、/usr/localにコピー


$ cd dtrace-78
$ mkdir -p obj sym dst
$ xcodebuild install -target ctfconvert -target ctfdump -target ctfmerge ARCHS="i386 x86_64" SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
$ sudo ditto $PWD/dst/usr/local /usr/local
Password:
$ cd ..

4.3 kext_toolsをビルドし、/usr/localにコピー


$ cd kext_tools-177.1
$ mkdir -p obj sym dst
$ xcodebuild install -target kextsymboltool -target setsegname ARCHS="i386 x86_64" SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
$ sudo ditto $PWD/dst/usr/local /usr/local
Password:
$ cd ..

4.4 bootstraps_cmdsをビルドし、/usr/localにコピー


$ cd bootstrap_cmds-72
$ mkdir -p obj sym dst
$ make install RC_ARCHS="i386" RC_CFLAGS="-arch i386 -pipe" RC_OS=macos RC_RELEASE=SnowLeopard SRCROOT=$PWD OBJROOT=$PWD/obj SYMROOT=$PWD/sym DSTROOT=$PWD/dst
$ sudo ditto $PWD/dst/usr/local /usr/local
Password:
$ cd ..

■5. カーネルをビルドする

5.1 Darwin xnu(カーネルソース)をダウンロード


$ curl -s -O http://www.opensource.apple.com/tarballs/xnu/xnu-1486.2.11.tar.gz

5.1 Darwin xnu(カーネルソース)を解凍


$ tar zxf xnu-1483.2.11.tar.gz

5.2 Darwin xnu(カーネルソース)をビルド


$ cd xnu-1486.2.11
$ make ARCH_CONFIGS="I386 X86_64" KERNEL_CONFIGS="RELEASE"
$ file BUILD/obj/RELEASE_*/mach_kernel
BUILD/obj/RELEASE_I386/mach_kernel: Mach-O executable i386
BUILD/obj/RELEASE_X86_64/mach_kernel: Mach-O 64-bit executable x86_64

 1. カーネルのビルド作業はCPUパワーに依存し、終了まで数分から数十分かかる。
 2. ビルドしたカーネルは、32bit用はRELEASE_I386、64bit用はRELEASE_X86_64に作成される。
 3. 日本語環境のターミナルでビルドすると、ビルド日付が漢字で挿入される為、アルファベットしか表示できない起動時のコンソールでは文字化けする。実用上問題ないが、気になる場合は、ビルド時のLANG環境変数をen_USに変更しておくと良い。

 ・参考情報:Darwinbuild(SSEN'S BLOG)

5.3 ユニバーサルバイナリに統合


$ lipo -create BUILD/obj/RELEASE_I386/mach_kernel BUILD/obj/RELEASE_X86_64/mach_kernel -output BUILD/obj/mach_kernel
$ file BUILD/obj/mach_kernel
BUILD/obj/mach_kernel: Mach-O universal binary with 2 architectures
BUILD/obj/mach_kernel (for architecture i386): Mach-O executable i386
BUILD/obj/mach_kernel (for architecture x86_64): Mach-O 64-bit executable x86_64

 ・ルートディレクトリ(/)にコピーし、既存のカーネルファイル(mach_kernel)と置き換えることで有効になる。

■応用編

1. ビルドしたカーネルの中身をデバッグする

 ビルドしたカーネルの中身をデバッグするため、binutils(Xcodeに含まれる)を使用しバイナリの中身を確認する。

1.1 hexdump 〜 バイナリをヘキサダンプする


bash-3.2# hexdump -n 512 -C /mach_kernel
00000000 ca fe ba be 00 00 00 03 01 00 00 07 00 00 00 03 |................|
00000010 00 00 10 00 00 55 14 63 00 00 00 0c 00 00 00 07 |.....U.c........|
00000020 00 00 00 03 00 55 30 00 00 71 88 85 00 00 00 0c |.....U0..q......|
00000030 00 00 00 12 00 00 00 00 00 c6 c0 00 00 56 3b 90 |.............V;.|
00000040 00 00 00 0c 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00000200

1.2 strings 〜 バイナリの中の文字列を表示する


bash-3.2# strings /mach_kernel | head -n 10
default_pager
vstruct zone
default memory manager
"%s[KERNEL]: %s"@/SourceCache/xnu/xnu-1486.2.11/osfmk/default_pager/default_pager.c:436
"can't start backing store monitor thread"@/SourceCache/xnu/xnu-1486.2.11/osfmk/default_pager/default_pager.c:319
alloc pager thread
"%s[KERNEL]: %s"@/SourceCache/xnu/xnu-1486.2.11/osfmk/default_pager/default_pager.c:176
alloc thread buffer
"%s[KERNEL]: %s"@/SourceCache/xnu/xnu-1486.2.11/osfmk/default_pager/default_pager.c:180
wire thread buffer

1.3 nm 〜 シンボルを表示する


bash-3.2# nm -l /mach_kernel | head -n 10
0083eb70 D .constructors_used
0083eb78 D .destructors_used
ff7f8000 A _APTD
feff7fc0 A _APTDpde
ff000000 A _APTmap
004470a2 T _AllocateNode
0021b372 T _Assert
0039efb5 T _BF_decrypt
0039eb6c T _BF_encrypt
0039f3fe T _BF_set_key

1.3 file 〜 ファイルタイプを表示する


bash-3.2# file /mach_kernel
/mach_kernel: Mach-O universal binary with 3 architectures
/mach_kernel (for architecture x86_64): Mach-O 64-bit executable x86_64
/mach_kernel (for architecture i386): Mach-O executable i386
/mach_kernel (for architecture ppc): Mach-O executable ppc

1.4 otool 〜 ニーモニックを表示する


bash-3.2# otool -t -v -V /mach_kernel | head -n 10
/mach_kernel:
(__TEXT,__text) section
_local_log2:
00201000 pushl %ebp
00201001 movl %esp,%ebp
00201003 movl 0x08(%ebp),%edx
00201006 xorl %eax,%eax
00201008 testl %edx,%edx
0020100a jne 0x00201011
0020100c jmp 0x00201016

2. Core i5/i7(Clarkdale/Arrandale)、AMD CPU対応のカーネルを作成する

2.1 10.6.2 カーネル(xnu-1486.2.11)にCore i5/i7/AMD CPU対応パッチをあてる


$ cd ~/Desktop/Dev
$ patch -p0 < albizu_10.2.diff
patching file xnu-1486.2.11/Makefile
patching file xnu-1486.2.11/bsd/kern/kern_mib.c
patching file xnu-1486.2.11/bsd/kern/mach_process.c
patching file xnu-1486.2.11/bsd/kern/uipc_socket.c
patching file xnu-1486.2.11/bsd/sys/msgbuf.h
patching file xnu-1486.2.11/config/version.c
patching file xnu-1486.2.11/iokit/IOKit/IOCatalogue.h
patching file xnu-1486.2.11/iokit/IOKit/IOCatalogue.h.orig
patching file xnu-1486.2.11/iokit/Kernel/IOCatalogue.cpp
patching file xnu-1486.2.11/iokit/Kernel/IOPlatformExpert.cpp
patching file xnu-1486.2.11/iokit/Kernel/IOStartIOKit.cpp
patching file xnu-1486.2.11/iokit/bsddev/IOKitBSDInit.cpp
patching file xnu-1486.2.11/libkern/c++/OSKext.cpp
patching file xnu-1486.2.11/libkern/c++/OSKext.cpp.orig
patching file xnu-1486.2.11/osfmk/conf/files.i386
patching file xnu-1486.2.11/osfmk/i386/.cpuid.c.swp
patching file xnu-1486.2.11/osfmk/i386/AT386/model_dep.c
patching file xnu-1486.2.11/osfmk/i386/acpi_wakeup.s
patching file xnu-1486.2.11/osfmk/i386/commpage/bcopy_sse3_64.s
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage.c
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage.c.orig
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage_asm.s
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage_mach_absolute_time.s
patching file xnu-1486.2.11/osfmk/i386/commpage/sse3emu.c
patching file xnu-1486.2.11/osfmk/i386/commpage/sse3emu.h
patching file xnu-1486.2.11/osfmk/i386/cpu_capabilities.h
patching file xnu-1486.2.11/osfmk/i386/cpu_capabilities.h.orig
patching file xnu-1486.2.11/osfmk/i386/cpu_topology.c
patching file xnu-1486.2.11/osfmk/i386/cpuid.c
patching file xnu-1486.2.11/osfmk/i386/cpuid.h
patching file xnu-1486.2.11/osfmk/i386/cpuid.h.orig
patching file xnu-1486.2.11/osfmk/i386/cpuid_legacy.h
patching file xnu-1486.2.11/osfmk/i386/i386_init.c
patching file xnu-1486.2.11/osfmk/i386/idt.s
patching file xnu-1486.2.11/osfmk/i386/idt64.s
patching file xnu-1486.2.11/osfmk/i386/lapic.c
patching file xnu-1486.2.11/osfmk/i386/pmCPU.c
patching file xnu-1486.2.11/osfmk/i386/pmCPU.c.orig
patching file xnu-1486.2.11/osfmk/i386/rtclock.c
patching file xnu-1486.2.11/osfmk/i386/rtclock.c.orig
patching file xnu-1486.2.11/osfmk/i386/rtclock.h
patching file xnu-1486.2.11/osfmk/i386/rtclock.h.orig
patching file xnu-1486.2.11/osfmk/i386/start.s
patching file xnu-1486.2.11/osfmk/i386/trap.h
patching file xnu-1486.2.11/osfmk/i386/tsc.c
patching file xnu-1486.2.11/osfmk/i386/tsc.h
patching file xnu-1486.2.11/osfmk/kern/Makefile
patching file xnu-1486.2.11/osfmk/kern/debug.c
patching file xnu-1486.2.11/osfmk/kern/voodoo_assert.h
patching file xnu-1486.2.11/pexpert/i386/pe_kprintf.c 
 ・参考情報 LINUX忘却録 diff / patch
  • legacy_kernelを64bitに対応させるパッチを適用(追記 2010/04/23)
 ・32/64bit legacy_kernel patch AnV_Qoopz_snow_leopard_xnu_rel2

It involved changing some assembly code with __LP64__ compiler check for passing 32/64 bit code (little 64bit code port).
 ・AnV_Qoopz_snow_leopard_xnu_rel2を適用

$ patch -p0 < AnV_Qoopz_snow_leopard_xnu_rel2.diff
patching file xnu-1486.2.11/Makefile
patching file xnu-1486.2.11/bsd/kern/kern_mib.c
patching file xnu-1486.2.11/bsd/kern/mach_process.c
patching file xnu-1486.2.11/bsd/kern/uipc_socket.c
patching file xnu-1486.2.11/bsd/sys/msgbuf.h
patching file xnu-1486.2.11/config/version.c
patching file xnu-1486.2.11/iokit/IOKit/IOCatalogue.h
patching file xnu-1486.2.11/iokit/Kernel/IOCatalogue.cpp
patching file xnu-1486.2.11/iokit/Kernel/IOPlatformExpert.cpp
patching file xnu-1486.2.11/iokit/Kernel/IOStartIOKit.cpp
patching file xnu-1486.2.11/iokit/bsddev/IOKitBSDInit.cpp
patching file xnu-1486.2.11/libkern/c++/OSKext.cpp
patching file xnu-1486.2.11/osfmk/conf/Makefile.i386
patching file xnu-1486.2.11/osfmk/conf/Makefile.ppc
patching file xnu-1486.2.11/osfmk/conf/Makefile.x86_64
patching file xnu-1486.2.11/osfmk/conf/files.i386
patching file xnu-1486.2.11/osfmk/conf/files.x86_64
patching file xnu-1486.2.11/osfmk/i386/AT386/model_dep.c
patching file xnu-1486.2.11/osfmk/i386/acpi_wakeup.s
patching file xnu-1486.2.11/osfmk/i386/commpage/bcopy_sse3_64.s
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage.c
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage_asm.s
patching file xnu-1486.2.11/osfmk/i386/commpage/commpage_mach_absolute_time.s
patching file xnu-1486.2.11/osfmk/i386/commpage/sse3emu.c
patching file xnu-1486.2.11/osfmk/i386/commpage/sse3emu.h
patching file xnu-1486.2.11/osfmk/i386/cpu_capabilities.h
patching file xnu-1486.2.11/osfmk/i386/cpu_topology.c
patching file xnu-1486.2.11/osfmk/i386/cpuid.c
patching file xnu-1486.2.11/osfmk/i386/cpuid.h
patching file xnu-1486.2.11/osfmk/i386/cpuid_legacy.h
patching file xnu-1486.2.11/osfmk/i386/i386_init.c
patching file xnu-1486.2.11/osfmk/i386/idt.s
patching file xnu-1486.2.11/osfmk/i386/idt64.s
patching file xnu-1486.2.11/osfmk/i386/lapic.c
patching file xnu-1486.2.11/osfmk/i386/pmCPU.c
patching file xnu-1486.2.11/osfmk/i386/rtclock.c
patching file xnu-1486.2.11/osfmk/i386/rtclock.h
patching file xnu-1486.2.11/osfmk/i386/start.s
patching file xnu-1486.2.11/osfmk/i386/trap.h
patching file xnu-1486.2.11/osfmk/i386/tsc.c
patching file xnu-1486.2.11/osfmk/i386/tsc.h
patching file xnu-1486.2.11/osfmk/kern/Makefile
patching file xnu-1486.2.11/osfmk/kern/debug.c
patching file xnu-1486.2.11/osfmk/kern/voodoo_assert.h
patching file xnu-1486.2.11/pexpert/i386/pe_kprintf.c

2.2 修正カーネルをビルドする


$ make ARCH_CONFIGS="I386" KERNEL_CONFIGS="RELEASE"
$ md5 BUILD/obj/RELEASE_I386/mach_kernel
MD5 (BUILD/obj/RELEASE_I386/mach_kernel) = e64772caa6cff8e44b887fe340f48823

2.3 10.6.3 カーネル(xnu-1504.3.12)にCore i5/i7(Clarkdale/Arrandale)/AMD CPU 対応のlegacy_kernelパッチをあてる


Standard fixes are included, plus a few extra stuff:
・Built-in kernel blacklister automatically blacklists bad kexts from loading. Therefore you don't need to use a disabler to disable it manually
・bigger dmesg Which translates to a larger log file so that you can troubleshoot easily
・uuid patching/fix Eliminates the need of UUID kext or specifying manually
・fsb detection
・cpu cache detection
・reboot fix- Eliminates the need of OpenHaltRestart and fixes shutdown/reboot issue
・sse3emu -SSE3 emulator for SSE2 processors . Bear in mind that most of the applications in Snow Leopard run fine with this emulator.

Some things added:
・some support for the new 6 core i7
・For people wanting to use XCode apps, I decided to add all the CHUD kexts to the kext blacklist. This means no more kp hell when installing and dealing with the development tools. If anyone thinks this is something that shouldn't be added, let me know.

Features in this specific package:
・If you have SleepEnabler installed, your SleepEnabler kext will get updated. If you don't use it, don't worry about it - it won't get installed.
・All of the CPUIDs in the new versions of programs from the 10.6.3 update will get patched. this means you don't need to deal with the hell regarding iTunes, etc.

(The actual patcher program also gets installed (/usr/local/bin/patcher, you can run from anyware via Terminal) as well as the CPUID text file (/Library/CPUIDs/*) Though this is only important to people who love control and want to be able to run it themselves :-P - this is all automated in the installer regardless. Unfortunately we still havent gotten on the fly patching working, so this is a reasonable fix for it for now.)

I do make cpuid files for updates and keep them online http://nawcom.com/osx86/cpuids/ for AMD people to use regarding updates as well as a nice frontend to Maxxuss' patcher app, drag and drop a cpuid.txt file onto the app to launch it - just like Taruga's HDA Patcher.
 ・10.6.3 legacy kernel for INTEL/AMDパッチを適用

$ patch -p0 < legacy_kernel-1504.3.12.diff
patching file xnu-1504.3.12/Makefile
patching file xnu-1504.3.12/bsd/kern/kern_mib.c
patching file xnu-1504.3.12/bsd/kern/mach_process.c
patching file xnu-1504.3.12/bsd/kern/uipc_socket.c
patching file xnu-1504.3.12/bsd/sys/msgbuf.h
patching file xnu-1504.3.12/config/version.c
patching file xnu-1504.3.12/iokit/IOKit/IOCatalogue.h
patching file xnu-1504.3.12/iokit/Kernel/IOCatalogue.cpp
patching file xnu-1504.3.12/iokit/Kernel/IOPlatformExpert.cpp
patching file xnu-1504.3.12/iokit/Kernel/IOStartIOKit.cpp
patching file xnu-1504.3.12/iokit/bsddev/IOKitBSDInit.cpp
patching file xnu-1504.3.12/libkern/c++/OSKext.cpp
patching file xnu-1504.3.12/osfmk/conf/files.i386
patching file xnu-1504.3.12/osfmk/i386/AT386/model_dep.c
patching file xnu-1504.3.12/osfmk/i386/acpi_wakeup.s
patching file xnu-1504.3.12/osfmk/i386/commpage/bcopy_sse3_64.s
patching file xnu-1504.3.12/osfmk/i386/commpage/commpage.c
patching file xnu-1504.3.12/osfmk/i386/commpage/commpage_asm.s
patching file xnu-1504.3.12/osfmk/i386/commpage/commpage_mach_absolute_time.s
patching file xnu-1504.3.12/osfmk/i386/commpage/sse3emu.c
patching file xnu-1504.3.12/osfmk/i386/commpage/sse3emu.h
patching file xnu-1504.3.12/osfmk/i386/cpu_capabilities.h
patching file xnu-1504.3.12/osfmk/i386/cpu_topology.c
patching file xnu-1504.3.12/osfmk/i386/cpuid.c
patching file xnu-1504.3.12/osfmk/i386/cpuid.h
patching file xnu-1504.3.12/osfmk/i386/cpuid_legacy.h
patching file xnu-1504.3.12/osfmk/i386/i386_init.c
patching file xnu-1504.3.12/osfmk/i386/idt.s
patching file xnu-1504.3.12/osfmk/i386/idt64.s
patching file xnu-1504.3.12/osfmk/i386/lapic.c
patching file xnu-1504.3.12/osfmk/i386/pmCPU.c
patching file xnu-1504.3.12/osfmk/i386/rtclock.c
patching file xnu-1504.3.12/osfmk/i386/rtclock.h
patching file xnu-1504.3.12/osfmk/i386/start.s
patching file xnu-1504.3.12/osfmk/i386/trap.h
patching file xnu-1504.3.12/osfmk/i386/tsc.c
patching file xnu-1504.3.12/osfmk/i386/tsc.h
patching file xnu-1504.3.12/osfmk/kern/Makefile
patching file xnu-1504.3.12/osfmk/kern/debug.c
patching file xnu-1504.3.12/osfmk/kern/voodoo_assert.h
patching file xnu-1504.3.12/pexpert/i386/pe_kprintf.c
$ make ARCH_CONFIGS="I386" KERNEL_CONFIGS="RELEASE"
$ md5 BUILD/obj/RELEASE_I386/mach_kernel
MD5 (BUILD/obj/RELEASE_I386/mach_kernel) = b8a03e979040e1a5cb0bb28c0735f675

3. ユニバーサルバイナリプログラムを作成する

3.1 Hello Worldをコンパイルする


$ cat hello.c
#include <stdio.h>

int main(void) {
printf("Hello World!!\n");
return 0;
}

$ cc -o hello hello.c
$ file hello
hello (for architecture i386): Mach-O executable i386

3.2 ユニバーサルバイナリでコンパイルする


$ cc -o hello -arch i386 -arch x86_64 hello.c
$ file hello
hello: Mach-O universal binary with 2 architectures
hello (for architecture i386): Mach-O executable i386
hello (for architecture x86_64): Mach-O 64-bit executable x86_64


最終更新:2010年06月05日 03:26