整理一下,反正一定會忘記,就放在這邊,也許以後會再新增
- gcc --save-temp hello.c
- gcc中間產生的檔案通通存起來
- gcc -dumpspecs
- 印spec,不過我完全看不懂
- gcc -dumpmachine
- 印出平台
因為用X用習慣了,常常會連線到另外遠端電腦,然後透過X把該台電腦軟體畫面輸出到本機。這時候的標準流程會是
每次都要打這些,還要查自己本機IP很煩。所以整理了兩光的script提供以後剪下貼上。
另外有人會問為什麼不直接用ssh -X
連過去?原因是因為我習慣設完display後,開一個遠端終端機丟在背景然後登出目前的ssh session,這樣的操作在ssh -X
下從來沒有成功過。我了遠端終端機後就算放在背景,一樣目前終端機會卡住。如果暴力把目前終端機關掉,那麼所有X的session都GG。實在懶得找原因,反正這是個workaround的世界(煙)。
上面操作中,本機需要設定
這兩個部份請自行估狗。
另外本機和遠端主機用相同的Distribution資訊如下,測試端的遠端主機是一台沒有GUI的Ubuntu server。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.2 LTS
Release: 14.04
Codename: trusty
把下面的描述放在~/.profile
最後面,下次ssh登入後就可以直接開啟X應用程式把畫面丟回本機了。
# Let's export DISPLAY if we are from ssh remote
if [ "$TERM" = "xterm" -a -n "$SSH_CLIENT" ] ; then
REMOTE_IP=$(echo $SSH_CLIENT | cut -f 1 -d " ")
if [ -z "$REMOTE_IP" ] ; then
exit 0
fi
export DISPLAY=$REMOTE_IP:0.0
fi
記得很久以前聽說在Linux執行檔案時,真正的起始點並不是main,加上之前有看到單純ld會幫你偷偷link一些沒看過的object檔案,所以這次就來看到底真相為何?
因為很假掰想要順便接觸一下ARM的組語,所以這次測試就使用Qemu跑ARM的Debian。
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 8.0 (jessie)
Release: 8.0
Codename: jessie
$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=571db48d9c9e4625b7da206e748e41c237f2b202, stripped
#include <stdio.h>
int main()
{
printf("Hello World\n");
return 0;
}
不知道各位還記得前面有提過,執行檔中有.text
的section。要執行的機械碼會放在這邊。我們先來看看hello1執行檔會從那邊開始?
$ readelf -h hello1
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: ARM
Version: 0x1
Entry point address: 0x102f0
Start of program headers: 52 (bytes into file)
...
Section header string table index: 33
從readelf可以看到起始點為0x102f0,那麼0x102f0是在那邊呢?我們再去看symbol table可以看到很巧的就是.text
的起始點。
$ objdump -t hello1
hello1: file format elf32-littlearm
SYMBOL TABLE:
00010134 l d .interp 00000000 .interp
...
000102f0 l d .text 00000000 .text
好了,那麼.text
這邊起始的程式是什麼?
Disassembly of section .text:
000102f0 <_start>:
102f0: e3a0b000 mov fp, #0
102f4: e3a0e000 mov lr, #0
102f8: e49d1004 pop {r1} ; (ldr r1, [sp], #4)
102fc: e1a0200d mov r2, sp
10300: e52d2004 push {r2} ; (str r2, [sp, #-4]!)
10304: e52d0004 push {r0} ; (str r0, [sp, #-4]!)
10308: e59fc010 ldr ip, [pc, #16] ; 10320 <_start+0x30>
1030c: e52dc004 push {ip} ; (str ip, [sp, #-4]!)
10310: e59f000c ldr r0, [pc, #12] ; 10324 <_start+0x34>
10314: e59f300c ldr r3, [pc, #12] ; 10328 <_start+0x38>
10318: ebffffeb bl 102cc <__libc_start_main@plt>
1031c: ebfffff0 bl 102e4 <abort@plt>
10320: 000104b4 .word 0x000104b4
10324: 00010420 .word 0x00010420
10328: 00010448 .word 0x00010448
很有趣,沒看到main()
,反而看到_start
。到底是_start
是什麼呢?還記得Linker script嗎?裏面有一個ENTRY
指令,可以指定程式從那邊開始跑,先來看一下預設的ENTRY
是不是也是_start
?
$ ld --verbose | grep ENTRY
ENTRY(_start)
目前我們只知道執行檔起始點是_start
,而不是main
,那顯然有人幫你把執行檔加碼,以至於你的執行檔出現了_start
。最偷懶的方式就是去找binary看看是不是有這樣的symbol。
user@host:/usr/lib$ find -name "*.[ao]" -exec nm -A {} \; 2> /dev/null | grep " _start$"
./arm-linux-gnueabi/crt1.o:00000000 T _start
./arm-linux-gnueabi/gcrt1.o:00000000 T _start
./arm-linux-gnueabi/Scrt1.o:00000000 T _start
./debug/usr/lib/arm-linux-gnueabi/crt1.o:00000000 T _start
./debug/usr/lib/arm-linux-gnueabi/gcrt1.o:00000000 T _start
./debug/usr/lib/arm-linux-gnueabi/Scrt1.o:00000000 T _start
OK,的確有object檔案裡面有_start
,我們再來確認編譯的時候會不會link這些檔案。
$ gcc -v hello1.c
Using built-in specs.
COLLECT_GCC=gcc
...
COLLECT_GCC_OPTIONS='-v' '-march=armv4t' '-mfloat-abi=soft'
...
-X --hash-style=gnu -m armelf_linux_eabi
...
/usr/lib/gcc/arm-linux-gnueabi/4.9/../../../arm-linux-gnueabi/crt1.o
...
而_start
會呼叫外部函數__libc_start_main
,我們透過LD_DEBUG
來看一下。
$ LD_DEBUG=all ./hello1 2>&1 |grep __libc_start_main
890: symbol=__libc_start_main; lookup in file=./hello1 [0]
890: symbol=__libc_start_main; lookup in file=/lib/arm-linux-gnueabi/libc.so.6 [0]
890: binding file ./hello1 [0] to /lib/arm-linux-gnueabi/libc.so.6 [0]: normal symbol `__libc_start_main' [GLIBC_2.4]
可以看到,在./hello1中有去找__libc_start_main
,最後去libc.so.6
找,並且找出libc.so.6
中__libc_start_main
的位址(即binding)。而__libc_start_main
的prototype如下
int __libc_start_main(int (*main) (int, char **, char **), int argc, char ** ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (*stack_end));
看到有趣的東西嘛?我有看到
從這邊我可以猜測這個函數就是呼叫一堆callback function,這些callback function就是上面列的死人骨頭。
從手冊的說明可以看到__libc_start_main()
是用來執行環境的初始化、呼叫main
函數並且傳遞參數,當main
函數結束後處理回傳值。手冊提到的範例詳細行為有
rtld_fini
註冊release callback function,當shared object結束時使用該callback釋放資源我們再回頭看看_start
的組合語言:
000102f0 <_start>:
102f0: e3a0b000 mov fp, #0
102f4: e3a0e000 mov lr, #0
102f8: e49d1004 pop {r1} ; (ldr r1, [sp], #4)
102fc: e1a0200d mov r2, sp
10300: e52d2004 push {r2} ; (str r2, [sp, #-4]!)
10304: e52d0004 push {r0} ; (str r0, [sp, #-4]!)
10308: e59fc010 ldr ip, [pc, #16] ; 10320 <_start+0x30>
1030c: e52dc004 push {ip} ; (str ip, [sp, #-4]!)
10310: e59f000c ldr r0, [pc, #12] ; 10324 <_start+0x34>
10314: e59f300c ldr r3, [pc, #12] ; 10328 <_start+0x38>
10318: ebffffeb bl 102cc <__libc_start_main@plt>
1031c: ebfffff0 bl 102e4 <abort@plt>
10320: 000104b4 .word 0x000104b4
10324: 00010420 .word 0x00010420
10328: 00010448 .word 0x00010448
有趣的地方是這3個位址
10320: 000104b4 .word 0x000104b4
10324: 00010420 .word 0x00010420
10328: 00010448 .word 0x00010448
從這邊可以看到這3個位址分別是
__libc_csu_fini
main
__libc_csu_init
也就是說,main
和__libc_csu_init
分別當作第一和第四參數傳給__libc_start_main
,而__libc_csu_fini
則被丟到stack,一樣傳給__libc_start_main
了。
Linux執行程式的起始點並不是main
,而是glibc binary中crt1.o
準備的_start
。這個start主要將你的main
,還有一些hook函數丟給__libc_start_main
,接下來libc的__libc_start_main
樵好事情後才真正執行你的main
,並且還要在main
結束後清理戰場。
$ cat hello1.dis
hello1: file format elf32-littlearm
Disassembly of section .init:
0001029c <_init>:
1029c: e92d4008 push {r3, lr}
102a0: eb000021 bl 1032c <call_weak_fn>
102a4: e8bd4008 pop {r3, lr}
102a8: e12fff1e bx lr
Disassembly of section .plt:
000102ac <puts@plt-0x14>:
102ac: e52de004 push {lr} ; (str lr, [sp, #-4]!)
102b0: e59fe004 ldr lr, [pc, #4] ; 102bc <_init+0x20>
102b4: e08fe00e add lr, pc, lr
102b8: e5bef008 ldr pc, [lr, #8]!
102bc: 00010318 .word 0x00010318
000102c0 <puts@plt>:
102c0: e28fc600 add ip, pc, #0, 12
102c4: e28cca10 add ip, ip, #16, 20 ; 0x10000
102c8: e5bcf318 ldr pc, [ip, #792]! ; 0x318
000102cc <__libc_start_main@plt>:
102cc: e28fc600 add ip, pc, #0, 12
102d0: e28cca10 add ip, ip, #16, 20 ; 0x10000
102d4: e5bcf310 ldr pc, [ip, #784]! ; 0x310
000102d8 <__gmon_start__@plt>:
102d8: e28fc600 add ip, pc, #0, 12
102dc: e28cca10 add ip, ip, #16, 20 ; 0x10000
102e0: e5bcf308 ldr pc, [ip, #776]! ; 0x308
000102e4 <abort@plt>:
102e4: e28fc600 add ip, pc, #0, 12
102e8: e28cca10 add ip, ip, #16, 20 ; 0x10000
102ec: e5bcf300 ldr pc, [ip, #768]! ; 0x300
Disassembly of section .text:
000102f0 <_start>:
102f0: e3a0b000 mov fp, #0
102f4: e3a0e000 mov lr, #0
102f8: e49d1004 pop {r1} ; (ldr r1, [sp], #4)
102fc: e1a0200d mov r2, sp
10300: e52d2004 push {r2} ; (str r2, [sp, #-4]!)
10304: e52d0004 push {r0} ; (str r0, [sp, #-4]!)
10308: e59fc010 ldr ip, [pc, #16] ; 10320 <_start+0x30>
1030c: e52dc004 push {ip} ; (str ip, [sp, #-4]!)
10310: e59f000c ldr r0, [pc, #12] ; 10324 <_start+0x34>
10314: e59f300c ldr r3, [pc, #12] ; 10328 <_start+0x38>
10318: ebffffeb bl 102cc <__libc_start_main@plt>
1031c: ebfffff0 bl 102e4 <abort@plt>
10320: 000104b4 .word 0x000104b4
10324: 00010420 .word 0x00010420
10328: 00010448 .word 0x00010448
0001032c <call_weak_fn>:
1032c: e59f3014 ldr r3, [pc, #20] ; 10348 <call_weak_fn+0x1c>
10330: e59f2014 ldr r2, [pc, #20] ; 1034c <call_weak_fn+0x20>
10334: e08f3003 add r3, pc, r3
10338: e7932002 ldr r2, [r3, r2]
1033c: e3520000 cmp r2, #0
10340: 012fff1e bxeq lr
10344: eaffffe3 b 102d8 <__gmon_start__@plt>
10348: 00010298 .word 0x00010298
1034c: 0000001c .word 0x0000001c
00010350 <deregister_tm_clones>:
10350: e59f301c ldr r3, [pc, #28] ; 10374 <deregister_tm_clones+0x24>
10354: e59f001c ldr r0, [pc, #28] ; 10378 <deregister_tm_clones+0x28>
10358: e0603003 rsb r3, r0, r3
1035c: e3530006 cmp r3, #6
10360: 912fff1e bxls lr
10364: e59f3010 ldr r3, [pc, #16] ; 1037c <deregister_tm_clones+0x2c>
10368: e3530000 cmp r3, #0
1036c: 012fff1e bxeq lr
10370: e12fff13 bx r3
10374: 000205ff .word 0x000205ff
10378: 000205fc .word 0x000205fc
1037c: 00000000 .word 0x00000000
00010380 <register_tm_clones>:
10380: e59f1024 ldr r1, [pc, #36] ; 103ac <register_tm_clones+0x2c>
10384: e59f0024 ldr r0, [pc, #36] ; 103b0 <register_tm_clones+0x30>
10388: e0601001 rsb r1, r0, r1
1038c: e1a01141 asr r1, r1, #2
10390: e0811fa1 add r1, r1, r1, lsr #31
10394: e1b010c1 asrs r1, r1, #1
10398: 012fff1e bxeq lr
1039c: e59f3010 ldr r3, [pc, #16] ; 103b4 <register_tm_clones+0x34>
103a0: e3530000 cmp r3, #0
103a4: 012fff1e bxeq lr
103a8: e12fff13 bx r3
103ac: 000205fc .word 0x000205fc
103b0: 000205fc .word 0x000205fc
103b4: 00000000 .word 0x00000000
000103b8 <__do_global_dtors_aux>:
103b8: e92d4010 push {r4, lr}
103bc: e59f401c ldr r4, [pc, #28] ; 103e0 <__do_global_dtors_aux+0x28>
103c0: e5d43000 ldrb r3, [r4]
103c4: e3530000 cmp r3, #0
103c8: 1a000002 bne 103d8 <__do_global_dtors_aux+0x20>
103cc: ebffffdf bl 10350 <deregister_tm_clones>
103d0: e3a03001 mov r3, #1
103d4: e5c43000 strb r3, [r4]
103d8: e8bd4010 pop {r4, lr}
103dc: e12fff1e bx lr
103e0: 000205fc .word 0x000205fc
000103e4 <frame_dummy>:
103e4: e92d4008 push {r3, lr}
103e8: e59f0028 ldr r0, [pc, #40] ; 10418 <frame_dummy+0x34>
103ec: e5903000 ldr r3, [r0]
103f0: e3530000 cmp r3, #0
103f4: 1a000001 bne 10400 <frame_dummy+0x1c>
103f8: e8bd4008 pop {r3, lr}
103fc: eaffffdf b 10380 <register_tm_clones>
10400: e59f3014 ldr r3, [pc, #20] ; 1041c <frame_dummy+0x38>
10404: e3530000 cmp r3, #0
10408: 0afffffa beq 103f8 <frame_dummy+0x14>
1040c: e1a0e00f mov lr, pc
10410: e12fff13 bx r3
10414: eafffff7 b 103f8 <frame_dummy+0x14>
10418: 000204e8 .word 0x000204e8
1041c: 00000000 .word 0x00000000
00010420 <main>:
10420: e92d4800 push {fp, lr}
10424: e28db004 add fp, sp, #4
10428: e59f0014 ldr r0, [pc, #20] ; 10444 <main+0x24>
1042c: ebffffa3 bl 102c0 <puts@plt>
10430: e3a03000 mov r3, #0
10434: e1a00003 mov r0, r3
10438: e24bd004 sub sp, fp, #4
1043c: e8bd4800 pop {fp, lr}
10440: e12fff1e bx lr
10444: 000104c8 .word 0x000104c8
00010448 <__libc_csu_init>:
10448: e92d43f8 push {r3, r4, r5, r6, r7, r8, r9, lr}
1044c: e59f6058 ldr r6, [pc, #88] ; 104ac <__libc_csu_init+0x64>
10450: e59f5058 ldr r5, [pc, #88] ; 104b0 <__libc_csu_init+0x68>
10454: e08f6006 add r6, pc, r6
10458: e08f5005 add r5, pc, r5
1045c: e0656006 rsb r6, r5, r6
10460: e1a07000 mov r7, r0
10464: e1a08001 mov r8, r1
10468: e1a09002 mov r9, r2
1046c: ebffff8a bl 1029c <_init>
10470: e1b06146 asrs r6, r6, #2
10474: 0a00000a beq 104a4 <__libc_csu_init+0x5c>
10478: e2455004 sub r5, r5, #4
1047c: e3a04000 mov r4, #0
10480: e2844001 add r4, r4, #1
10484: e5b53004 ldr r3, [r5, #4]!
10488: e1a00007 mov r0, r7
1048c: e1a01008 mov r1, r8
10490: e1a02009 mov r2, r9
10494: e1a0e00f mov lr, pc
10498: e12fff13 bx r3
1049c: e1540006 cmp r4, r6
104a0: 1afffff6 bne 10480 <__libc_csu_init+0x38>
104a4: e8bd43f8 pop {r3, r4, r5, r6, r7, r8, r9, lr}
104a8: e12fff1e bx lr
104ac: 00010088 .word 0x00010088
104b0: 00010080 .word 0x00010080
000104b4 <__libc_csu_fini>:
104b4: e12fff1e bx lr
Disassembly of section .fini:
000104b8 <_fini>:
104b8: e92d4008 push {r3, lr}
104bc: e8bd4008 pop {r3, lr}
104c0: e12fff1e bx lr
安裝順序如下
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.1 LTS
Release: 14.04
Codename: trusty
$ sudo apt-get install qemu-system-arm
$ qemu-system-arm -machine help
Supported machines are:
versatileab ARM Versatile/AB (ARM926EJ-S)
versatilepb ARM Versatile/PB (ARM926EJ-S)
lm3s811evb Stellaris LM3S811EVB
...
安裝ARM版本Debian需要
先抓平台相關的kernel和initrd,路徑如下
http://host/debian/dists/Debian7.8/main/installer-armel/20130430/images/
下面有不同的ARM平台,還記得上面qemu-system-arm -machine help
,請和這邊目錄下的比對,挑一個順眼的。我使用
versatile,所以就切到下面的目錄
http://host/debian/dists/Debian7.8/main/installer-armel/20130430/images/versatile/netboot/
把下面的兩個檔案拉下來
接下來在同樣的主機上,下載ISO檔。
http://host/debian-cd/7.8.0/armel
透過下面的指令安裝虛擬磁碟,請自行決定大小
$ qemu-img create debian.img 8G
然後叫qemu載入ARM kernel,initrd,以及ISO
$ qemu-system-arm -M versatileab -kernel ./vmlinuz-3.2.0-4-versatile -initrd ./initrd.gz -cdrom ./debian-7.8.0-armel-DVD-1.iso -hda debian.img -m 1024
這邊可以看到versatileab又出現了,請往上找一下這個字串吧。
最tricky的地方在這邊,理論上你要透過loopback裝置mount 虛擬磁碟,複製/boot就可以了。但是現實就是,因為磁碟機/root的partition有offset,所以直接mount程式無法辨認Filesystem所以無法mount。正確方式如下
$ sudo fdisk -l -u debian.img
Disk debian.img: 8589 MB, 8589934592 bytes
255 heads, 63 sectors/track, 1044 cylinders, total 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000823a0
Device Boot Start End Blocks Id System
debian.img1 2048 15988735 7993344 83 Linux
debian.img2 15990782 16775167 392193 5 Extended
debian.img5 15990784 16775167 392192 82 Linux swap / Solaris
有兩個東西要注意
所以正確的mount方式如下
$ sudo mount -o loop,offset=$((2048 * 512)) debian.img /mnt
接下來抽出就簡單了,請在剛才安裝的虛擬磁碟檔案同一個目錄操作。
$ mkdir boot
$ cp /mnt/boot/* boot/ -rv
這邊就照表操課,我有指定localhost將port 2222 forward到Qemu的port 22,以便將來ssh進去
$ qemu-system-arm -M versatileab -kernel ./boot/vmlinuz-3.2.0-4-versatile -initrd ./boot/initrd.img-3.2.0-4-versatile -hda debian.img -m 1024 -append "root=/dev/sda1" -redir tcp:2222::22
驗收看看是不是真的可以連進去,並且裏面真的是ARM的binary?
$ ssh -p 2222 user@localhost
user@localhost's password:
Linux debian 3.2.0-4-versatile #1 Debian 3.2.65-1+deb7u1 armv5tejl
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have mail.
Last login: Fri Feb 6 09:35:07 2015
user@debian:~$ file /bin/ls
/bin/ls: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0x5bc97dbca9ac168932d898a5e2eaf68e8fde5e16, stripped
先來個小故事,某天組裝工趁放假跑去看老房子。發現只有一間上面有動物的造型。因為年代久遠,只看得出來有四肢腳而已,而不知道是那種動物。好奇之餘問了店家,店家說他們承租,不知道那是什麼東西。後來一位長者經過,就順便請教他同一個問題,長者說他住這邊好幾年都不知道上面有這東西。最後遇到當地文史工作室才知道是當時主人的商標,一隻獅子。
我們常常用的東西,因為太習以為常,以至於發生視而不見的狀況屢見不鮮。但是惡魔就在細節裏面,而長時間地視而不見就會把自己對於這樣的事物感受性變低。
回到主體。組裝的時候,常常缺東缺西的。這時候就需要cross-compile一些套件頂一下,所以如果有人組裝過的話,應該會對下面的命令倍感親切。
$ ./configure --host=mipsel
如果組裝夠次數夠多,也會看到--target
和--build
的參數似乎和這個有關。找時間稍微了解一下
對於--target目前手上的資料無法讓我完全理解,請注意!
根據Autoconf手冊說明,這些參數的預設值如下:
--build
--host
--build
相同--target
--host
相同因為這樣的連動性,如果你要cross-compile,那麼下了--host
後麻煩不要省掉--build
,不然autotool會把build設成和host一樣。
Automake手冊裏面的定義
--build
--host
--target
--host
一樣同樣的平台,根據上面的連動,你設了--host
就可以省略這個選項Autotool選擇gcc的方式如下
--host
和--build
相同
--host
和--build
不同
--target
的為gcc的prefix--host=xxx
, --target=zzz
,會使用zzz-gcc產生xxx平台的機械碼看的有點混亂嘛?沒關係,autoconf 2.69手冊有提到,要cross-compile的話,唯一(if and only if)的條件就是指令--host
指定和你現在的平台不同就好。
在組裝的過程中,常常會遇到用source去載入一個shell script,裏面通常是一組的環境變數。然而如果專案大到某個程度,這個script就會塞入很多複雜的function,例如某專案的build/envsetup.sh。這時候要去trace用肉眼去看實在是太過殘酷,最近為了這個問題想到了一招很簡單的方式,那就是:
$ bash -x
沒錯就這麼簡單,直接來看例子吧。首先我們有一個script裏面有function。
#!/bin/bash
function whatsoever()
{
echo "My code works, I don't know why."
}
接下來就是剛才講的操作
$ bash -x
+ '[' -z '\s-\v\$ ' ']'
+ shopt -s checkwinsize
... # 中間發生超多事,有興趣自行研究。發現好玩的再跟我說。
$ cd /tmp
+ cd /tmp
$ . demo.sh
+ . demo.sh
$ whatsoever
+ whatsoever
+ echo 'My code works, I don'\''t know why.'
My code works, I don't know why.
打完收工,謝謝收看。
網友Scott Tasi大大說這個方式和下面的方式相同:
set -x
我就學天線寶寶再重複一下實驗
$ set -x
$ . demo.sh
+ . demo.sh
$ whatsoever
+ whatsoever
+ echo 'My code works, I don'\''t know why.'
My code works, I don't know why.
$ set +x
+ set +x
$ whatsoever
My code works, I don't know why.
結論就是,用set -x
,set +x
就可以了。不過bash -x
跑出來的訊息還真的嚇了我一跳,原來載入一個bash有那麼東的東西要做。這就是所謂的微言大意嗎?
好吧,這個標題我也不滿意,不過就將就一下吧。
簡單來說在Ubuntu內只要可以找得到的distribution,你就有辦法讓它在你的Ubuntu使用。使用順序如下:
命令:
debootstrap --arch=你要跑的target平台 --variant=minbase 你要跑的版本代號 自己PC的版本代號 [mirror site]
要怎麼知道arch有哪些呢,你可以連到任意一個Ubuntu archive中的ubuntu/dists/[版本代號]/main中就可以看到了。可以看範例網頁,這邊可以看到有i386
和amd64
兩種架構。
而版本代號可以在任意一個Ubuntu archive中的ubuntu/dists/看到。範例網頁可以看到10.04 (lucid), 12.04 (precise)等。
另外--variant問男人可以看到有
我使用的範例如下:我要在x86-64位元的Ubuntu 14.04 (trusty) 下面安裝32位元(i386)的10.04 (lucid)最少套件的話,就會使用下面的指令。
$ sudo debootstrap --arch=i386 --variant=minbase lucid trusty ftp://ftp.tku.edu.tw/ubuntu/
I: Retrieving Release
I: Retrieving Release.gpg
I: Checking Release signature
...
I: Unpacking apt...
I: Configuring the base system...
I: Configuring apt...
I: Configuring libc-bin...
I: Base system installed successfully.
debootstrap會把下載並解開的套件放在你的指定的target名稱目錄中,這次範例使用trusty,所以我們看看trusty目錄有什麼東西?
$ cd trusty
$ tree -L 1 -d
.
├── bin
├── boot
├── dev
├── etc
├── home
├── lib
├── media
├── mnt
├── opt
├── proc
├── root
├── sbin
├── selinux
├── srv
├── sys
├── tmp
├── usr
└── var
可以看到他就是一個root file system。接下來要做的就是。
先確認我電腦上的Ubuntu版本
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.1 LTS
Release: 14.04
Codename: trusty
$ file /bin/ls
/bin/ls: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=64d095bc6589dd4bfbf1c6d62ae985385965461b, stripped
切換指令如下
$ cd trusty # 假設你還沒切換過去
$ sudo mount --bind /dev ./dev
$ sudo mount --bind /dev/pts ./dev/pts
$ sudo mount --bind /proc ./proc
$ sudo mount --bind /sys ./sys
$ sudo chroot .
好啦,口說無憑,我們先來看看是不是真的換到lucid,32位元版本吧
# apt-get install lsb-release # 因為最少安裝所以沒有lsb_release
Reading package lists... Done
Building dependency tree... Done
...
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 10.04 LTS
Release: 10.04
Codename: lucid
# file /bin/ls
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped
這東西能做什麼呢?有時候開發套件需要在不同的Ubuntu版本測試,這時候後這招頂著先應該會比用VM再來得有效率一些。
另外要注意的是,我測試的時候自己的電腦應該有裝過很多東西了。這表示你要按表操課可能會因為缺乏套件所以不會成功,例如debootstrap可能就要自行安裝了我猜。
嘛,這就是人參,出現這種狀況就當作磨練吧。
OK. This should be the first English article in my blog. I do hope this will also be the last one. English is not my mother tongue, so please bear with that. It should be clear to address my point of view although there should be some glitches throughout my article.
The purpose of my technical articles and slides is to provide useful information for the people who uses Chinese. Since I went to college to learn computer engineering, what I saw in the class and laboratory meetings, the slides always wrote in English. Even after I graduated, it still mostly true in the events or presentations I attended locally. However, most professors and speakers uses mandarin to describe their ideas and thoughts. It is rare to have a completed English presentation in those scenarios, never to say discuss in English. If that so, why people uses English in their slides?
Don’t get me wrong. I totally agree English is extremely important in information technology area. Most of the first hand information writes in English. If you need to cooperate with people overseas, you use English. However, the scenario I call into question is that if your audiences uses mandarin, you speak in mandarin, why bother to write slides in English? Can you make sure what you wrote are 100% grammar corrected? Will this exclude the newbie who does not familiar in English yet if they search keyword in the Internet? A ideal article in the Internet should be useful for the people who need it. If you write your article and slide in Chinese, you will benefit the people who uses Chinese. There are already plenty of useful information in English. Why don’t you just use your mother tongue to describe your thought and what you found?