2017年9月15日 星期五

pascal 編譯/執行 (0) - 使用 free pascal 編譯出 x86_32 的執行檔

在 rust 大戰 c/c++ 時, 我們似乎忘了還有一個系統層級的語言 pascal, pascal 也沒有 gc, 也是編譯型語言, dos 時代的 turbo pascal, windows 時代的 delphi, 是 pascal 風光的時候, 為什麼突然沒落了, 真是奇怪。我突然對 pascal 有了興趣, 來把玩一下這個傳統的語言。

在談論 x86 32bit 模式之前, 先來看看預設的 x86 64bit 怎麼編譯。

environment:
linux 64bit/debian

在 linux 下有 free pascal 編譯器可用, x86 64bit 系統預設的 ppcx64 只能編譯出 x64 執行檔, 先來看看怎麼使用 free pascal 編譯器。

p1.pas
 1 {$CALLING PASCAL}
 2 Program h;
 3 (*Uses f1, Crt in '/usr/local/lib/fpc/3.1.1/units/i386-linux/rtl-console/crt.ppu';*)
 4 Uses f1, Crt;
 5 
 6 
 7 var x, v: integer;
 8 var str: string;
 9 begin
10 
11   str := 'abc';
12 
13 (*  x := max(5,6); *)
14   x := 7;
15   Writeln('hello free pascal, max: ', x, str);
16 end.

apt-get install fpc           # 安裝 free pascal 編譯器。
fpc p1.pas                    # 編譯 p1.pas
./p1                          # 執行
hello free pascal, max: 7abc  # 執行結果

p1.pas 很簡單的把 int, string 變數用 Writeln 印出來, 不需要像 c printf 用那些老是記不住的 %d, %u, %lld, 還蠻方便的, 這是怎麼做到的? 真令人好奇。

因為只看得懂 x86 32bit 組合語言, 所以我還是很需要可以建構出 32bit 環境的開發工具。

x86 64bit 系統預設的 ppcx64 無法編譯出 x86 32bit code 的程式, 需要自己編譯 32bit 的版本, 參考《From Linux x64 to Linux i386》建構可以 build x86 32bit code 的 pascal compiler。

下載 freepascal source code
https://github.com/graemeg/freepascal.git

還要先安裝 free pascal compiler, free pascal compiler 是用 pascal 寫的。
apt-get install fp-compiler

From Linux x64 to Linux i386
以下是參考《From Linux x64 to Linux i386》的內容

當然要先安裝 x86 32bit 開發工具, 請參考《在 debian 上安裝 x86 32bit gcc/g++

再來是建立 /usr/bin/i386-linux-as, /usr/bin/i386-linux-ld 這 2 個 script, 記得
chmod 755 /usr/bin/i386-linux-as /usr/bin/i386-linux-ld 
給他們執行權限。

/usr/bin/i386-linux-as
1 #!/bin/bash
2 as --32 $@

/usr/bin/i386-linux-ld
1 #!/bin/bash
2 ld -A elf32-i386 $@

以下指令分別是 "編譯" 以及 "安裝"
compile and install command
1 make all CPU_TARGET=i386
2 sudo make crossinstall CPU_TARGET=i386

會安裝到
/usr/local/lib/fpc/3.1.1/

h.pas
 1 Program h;
 2 Uses Crt in '/usr/local/lib/fpc/3.1.1/units/i386-linux/rtl-console/crt.ppu';
 3 
 4   var x, v: integer;
 5 begin
 6 
 7   x := 5;
 8   v := 6;
 9   Writeln('hello free pascal, max: ', x);
10   Writeln('hello free pascal, min: ', v);
11 end.

編譯 h.pas 與執行
 1 descent@debian64:pascal$ /usr/local/lib/fpc/3.1.1/ppcross386 h.pas
 2 Free Pascal Compiler version 3.1.1 [2017/03/27] for i386
 3 Copyright (c) 1993-2017 by Florian Klaempfl and others
 4 Target OS: Linux for i386
 5 Compiling h.pas
 6 Linking h
 7 11 lines compiled, 0.3 sec
 8 descent@debian64:pascal$ ./h 
 9 hello free pascal, max: 5
10 hello free pascal, min: 6

That's it. Edit your /etc/fpc.cfg file if needed.

得到 h.s 的組合語言檔案
/usr/local/lib/fpc/3.1.1/ppcross386 -g -al -Cn h.pas

h.s L86, 87 是呼叫 min 這個 function, 可是卻不是用 pascal call convention 而是使用 register 傳遞參數, 但我加上 {$CALLING PASCAL} 卻沒有看到期待的 pascal call convention。






ModifierPushing orderStack cleaned byalignment





¡none¿Left-to-rightCalleedefault
registerLeft-to-rightCalleedefault
cdeclRight-to-leftCallerGCC alignment
interruptRight-to-leftCalleedefault
pascalLeft-to-rightCalleedefault
safecallRight-to-leftCalleedefault
stdcallRight-to-leftCalleeGCC alignment
oldfpccallRight-to-leftCalleedefault





h.s L58 ~ 60, free pascal compiler 也幫我們產生一個像 c main function 的組合語言。

h.s
  1  .file "h.pas"
  2 # Begin asmlist al_begin
  3 
  4 .section .text.b_DEBUGSTART_$P$H
  5  .balign 4,0x90
  6 .globl DEBUGSTART_$P$H
  7  .type DEBUGSTART_$P$H,@object
  8 DEBUGSTART_$P$H:
  9  .stabs "/media/work/git/progs/pascal/",100,0,0,.Lf2
 10  .stabs "h.pas",100,0,0,.Lf2
 11 .Lf2:
 12 # End asmlist al_begin
 13 # Begin asmlist al_stabs
 14 
 15 .section .data.n_H
 16  .balign 4
 17 .globl DEBUGINFO_$P$H
 18  .type DEBUGINFO_$P$H,@object
 19 DEBUGINFO_$P$H:
 20 # Defs - Begin unit SYSTEM has index 1
 21  .stabs "void:t2=2",128,0,0,0
 22  .stabs "SMALLINT:t1=@s16;r1;-32768;32767;",128,0,0,0
 23 # Defs - End unit SYSTEM has index 1
 24 # Defs - Begin unit FPINTRES has index 2
 25 # Defs - End unit FPINTRES has index 2
 26 # Defs - Begin unit F1 has index 3
 27 # Defs - End unit F1 has index 3
 28 # Defs - Begin unit UNIXTYPE has index 8
 29 # Defs - End unit UNIXTYPE has index 8
 30 # Defs - Begin unit BASEUNIX has index 5
 31 # Defs - End unit BASEUNIX has index 5
 32 # Defs - Begin unit UNIXUTIL has index 9
 33 # Defs - End unit UNIXUTIL has index 9
 34 # Defs - Begin unit SYSCALL has index 10
 35 # Defs - End unit SYSCALL has index 10
 36 # Defs - Begin unit UNIX has index 6
 37 # Defs - End unit UNIX has index 6
 38 # Defs - Begin unit TERMIO has index 7
 39 # Defs - End unit TERMIO has index 7
 40 # Defs - Begin unit CRT has index 4
 41 # Defs - End unit CRT has index 4
 42 # Defs - Begin unit SI_PRC has index 10
 43 # Defs - End unit SI_PRC has index 10
 44 # Defs - Begin Staticsymtable
 45 # Defs - End Staticsymtable
 46 # Syms - Begin Staticsymtable
 47  .stabs "X:S1",38,0,5,U_$P$H_$$_X
 48  .stabs "V:S1",38,0,5,U_$P$H_$$_V
 49 # Syms - End Staticsymtable
 50 # End asmlist al_stabs
 51 # Begin asmlist al_procedures
 52 
 53 .section .text.n_main
 54  .balign 16,0x90
 55 .globl PASCALMAIN
 56  .type PASCALMAIN,@function
 57 PASCALMAIN:
 58 .globl main
 59  .type main,@function
 60 main:
 61  .stabs "main:F2",36,0,5,main
 62 .Lc1:
 63  .stabs "h.pas",132,0,0,.Lf1
 64 .Lf1:
 65  .stabn 68,0,6,.Ll1 - main
 66 .Ll1:
 67 # [h.pas]
 68 # [6] begin
 69  pushl %ebp
 70 .Lc3:
 71 .Lc4:
 72  movl %esp,%ebp
 73 .Lc5:
 74  pushl %ebx
 75  call fpc_initializeunits
 76  .stabn 68,0,8,.Ll2 - main
 77 .Ll2:
 78 # [8] x := max(5,6);
 79  movw $6,%dx
 80  movw $5,%ax
 81  call F1_$$_MAX$SMALLINT$SMALLINT$$SMALLINT
 82  movw %ax,U_$P$H_$$_X
 83  .stabn 68,0,9,.Ll3 - main
 84 .Ll3:
 85 # [9] v := min(5,6);
 86  movw $6,%dx
 87  movw $5,%ax
 88  call F1_$$_MIN$SMALLINT$SMALLINT$$SMALLINT
 89  movw %ax,U_$P$H_$$_V
 90  .stabn 68,0,10,.Ll4 - main
 91 .Ll4:
 92 # [10] Writeln('hello free pascal, max: ', x);
 93  call fpc_get_output
 94  movl %eax,%ebx
 95  movl $_$H$_Ld1,%ecx
 96  movl %ebx,%edx
 97  movl $0,%eax
 98  call fpc_write_text_shortstr
 99  call fpc_iocheck
100  movswl U_$P$H_$$_X,%ecx
101  movl %ebx,%edx
102  movl $0,%eax
103  call fpc_write_text_sint
104  call fpc_iocheck
105  movl %ebx,%eax
106  call fpc_writeln_end
107  call fpc_iocheck
108  .stabn 68,0,11,.Ll5 - main
109 .Ll5:
110 # [11] Writeln('hello free pascal, min: ', v);
111  call fpc_get_output
112  movl %eax,%ebx
113  movl $_$H$_Ld2,%ecx
114  movl %ebx,%edx
115  movl $0,%eax
116  call fpc_write_text_shortstr
117  call fpc_iocheck
118  movswl U_$P$H_$$_V,%ecx
119  movl %ebx,%edx
120  movl $0,%eax
121  call fpc_write_text_sint
122  call fpc_iocheck
123  movl %ebx,%eax
124  call fpc_writeln_end
125  call fpc_iocheck
126  .stabn 68,0,12,.Ll6 - main
127 .Ll6:
128 # [12] end.
129  call fpc_do_exit
130  popl %ebx
131  movl %ebp,%esp
132  popl %ebp
133  ret
134 .Lc2:
135 .Le0:
136  .size main, .Le0 - main
137  .stabn 192,0,0,0
138  .stabn 224,0,0,.Lt1-main
139 .Lt1:
140 
141 .section .text
142 
143 .section .fpc.n_links
144  .long DEBUGINFO_$P$H
145  .long DEBUGSTART_$P$H
146  .long DEBUGEND_$P$H
147 # End asmlist al_procedures
148 # Begin asmlist al_globals
149 
150 .section .bss
151  .balign 2
152 # [5] var x, v: integer;
153  .type U_$P$H_$$_X,@object
154  .size U_$P$H_$$_X,2
155 U_$P$H_$$_X:
156  .zero 2
157 
158 .section .bss
159  .balign 2
160  .type U_$P$H_$$_V,@object
161  .size U_$P$H_$$_V,2
162 U_$P$H_$$_V:
163  .zero 2
164 
165 .section .data.n_INITFINAL
166  .balign 4
167 .globl INITFINAL
168  .type INITFINAL,@object
169 INITFINAL:
170  .long 3,0
171  .long INIT$_$SYSTEM
172  .long 0
173  .long INIT$_$UNIX
174  .long FINALIZE$_$UNIX
175  .long INIT$_$CRT
176  .long FINALIZE$_$CRT
177 .Le1:
178  .size INITFINAL, .Le1 - INITFINAL
179 
180 .section .data.n_FPC_THREADVARTABLES
181  .balign 4
182 .globl FPC_THREADVARTABLES
183  .type FPC_THREADVARTABLES,@object
184 FPC_THREADVARTABLES:
185  .long 1
186  .long THREADVARLIST_$SYSTEM$indirect
187 .Le2:
188  .size FPC_THREADVARTABLES, .Le2 - FPC_THREADVARTABLES
189 
190 .section .data.n_FPC_RESOURCESTRINGTABLES
191  .balign 4
192 .globl FPC_RESOURCESTRINGTABLES
193  .type FPC_RESOURCESTRINGTABLES,@object
194 FPC_RESOURCESTRINGTABLES:
195  .long 0
196 .Le3:
197  .size FPC_RESOURCESTRINGTABLES, .Le3 - FPC_RESOURCESTRINGTABLES
198 
199 .section .data.n_FPC_WIDEINITTABLES
200  .balign 4
201 .globl FPC_WIDEINITTABLES
202  .type FPC_WIDEINITTABLES,@object
203 FPC_WIDEINITTABLES:
204  .long 0
205 .Le4:
206  .size FPC_WIDEINITTABLES, .Le4 - FPC_WIDEINITTABLES
207 
208 .section .data.n_FPC_RESSTRINITTABLES
209  .balign 4
210 .globl FPC_RESSTRINITTABLES
211  .type FPC_RESSTRINITTABLES,@object
212 FPC_RESSTRINITTABLES:
213  .long 0
214 .Le5:
215  .size FPC_RESSTRINITTABLES, .Le5 - FPC_RESSTRINITTABLES
216 
217 .section .fpc.n_version
218  .balign 8
219  .type __fpc_ident,@object
220 __fpc_ident:
221  .ascii "FPC 3.1.1 [2017/03/27] for i386 - Linux"
222 .Le6:
223  .size __fpc_ident, .Le6 - __fpc_ident
224 
225 .section .data.n___stklen
226  .balign 4
227 .globl __stklen
228  .type __stklen,@object
229 __stklen:
230  .long 8388608
231 .Le7:
232  .size __stklen, .Le7 - __stklen
233 
234 .section .data.n___heapsize
235  .balign 4
236 .globl __heapsize
237  .type __heapsize,@object
238 __heapsize:
239  .long 0
240 .Le8:
241  .size __heapsize, .Le8 - __heapsize
242 
243 .section .data.n___fpc_valgrind
244  .balign 4
245 .globl __fpc_valgrind
246  .type __fpc_valgrind,@object
247 __fpc_valgrind:
248  .byte 0
249 .Le9:
250  .size __fpc_valgrind, .Le9 - __fpc_valgrind
251 
252 .section .data.n_FPC_RESLOCATION
253  .balign 4
254 .globl FPC_RESLOCATION
255  .type FPC_RESLOCATION,@object
256 FPC_RESLOCATION:
257  .long 0
258 .Le10:
259  .size FPC_RESLOCATION, .Le10 - FPC_RESLOCATION
260 # End asmlist al_globals
261 # Begin asmlist al_typedconsts
262 
263 .section .rodata.n__$H$_Ld1
264  .balign 4
265 .globl _$H$_Ld1
266 _$H$_Ld1:
267  .ascii "\030hello free pascal, max: \000"
268 .Le11:
269  .size _$H$_Ld1, .Le11 - _$H$_Ld1
270 
271 .section .rodata.n__$H$_Ld2
272  .balign 4
273 .globl _$H$_Ld2
274 _$H$_Ld2:
275  .ascii "\030hello free pascal, min: \000"
276 .Le12:
277  .size _$H$_Ld2, .Le12 - _$H$_Ld2
278 # End asmlist al_typedconsts
279 # Begin asmlist al_dwarf_frame
280 
281 .section .debug_frame
282 .Lc6:
283  .long .Lc8-.Lc7
284 .Lc7:
285  .long -1
286  .byte 1
287  .byte 0
288  .uleb128 1
289  .sleb128 -4
290  .byte 8
291  .byte 12
292  .uleb128 4
293  .uleb128 4
294  .byte 5
295  .uleb128 8
296  .uleb128 1
297  .balign 4,0
298 .Lc8:
299  .long .Lc10-.Lc9
300 .Lc9:
301  .long .Lc6
302  .long .Lc1
303  .long .Lc2-.Lc1
304  .byte 4
305  .long .Lc3-.Lc1
306  .byte 14
307  .uleb128 8
308  .byte 4
309  .long .Lc4-.Lc3
310  .byte 5
311  .uleb128 5
312  .uleb128 2
313  .byte 4
314  .long .Lc5-.Lc4
315  .byte 13
316  .uleb128 5
317  .balign 4,0
318 .Lc10:
319 # End asmlist al_dwarf_frame
320 # Begin asmlist al_end
321 
322 .section .text.z_DEBUGEND_$P$H
323  .balign 4,0x90
324 .globl DEBUGEND_$P$H
325  .type DEBUGEND_$P$H,@object
326 DEBUGEND_$P$H:
327  .stabs "",100,0,0,.Lf3
328 .Lf3:
329 # End asmlist al_end
330 .section .note.GNU-stack,"",%progbits

從 h.s L92 可以得知, Writeln 被換成很多 call XXX, 直到 call fpc_writeln_end 時, 才會在終端機印出字串。

我不知道 Writeln 是不是被稱為 function, 但至少和 c function 是完全不同的概念, 有點類似語言內建的 '指令'。而我寫的 function max, 被換成 F1_$$_MAX$SMALLINT$SMALLINT$$SMALLINT 這樣的名稱, 呼叫 max 時, 也只有
call    F1_$$_MAX$SMALLINT$SMALLINT$$SMALLINT
符合想像的那樣。這就是語言內建 IO, 而 C 語言沒有內建 IO 的意思, C 的 IO 得靠 printf function 來完成, 語言不提供這樣的 '指令'。

free pascal compiler 在編譯時, 會產生 ppas.sh link.res。
ppas.sh - 編譯 script
link.res - linker script

 1 #!/bin/sh
 2 DoExitAsm ()
 3 { echo "An error occurred while assembling $1"; exit 1; }
 4 DoExitLink ()
 5 { echo "An error occurred while linking $1"; exit 1; }
 6 echo Linking h
 7 OFS=$IFS
 8 IFS="
 9 "
10 /usr/bin/ld -b elf32-i386 -m elf_i386      -L. -o h -T link.res -e _start
11 if [ $? != 0 ]; then DoExitLink h; fi
12 IFS=$OFS

link.res
  1 SEARCH_DIR("/usr/lib/i386-linux-gnu/")
  2 SEARCH_DIR("/lib/")
  3 SEARCH_DIR("/usr/lib/")
  4 SEARCH_DIR("/usr/lib/ruby/")
  5 SEARCH_DIR("/usr/lib/modules-load.d/")
  6 SEARCH_DIR("/usr/lib/ipxe/")
  7 SEARCH_DIR("/usr/lib/dbus-1.0/")
  8 SEARCH_DIR("/usr/lib/libgksu/")
  9 SEARCH_DIR("/usr/lib/pkgconfig/")
 10 SEARCH_DIR("/usr/lib/gcr/")
 11 SEARCH_DIR("/usr/lib/caja/")
 12 SEARCH_DIR("/usr/lib/exim4/")
 13 SEARCH_DIR("/usr/lib/apache2/")
 14 SEARCH_DIR("/usr/lib/graphviz/")
 15 SEARCH_DIR("/usr/lib/libblas/")
 16 SEARCH_DIR("/usr/lib/python3/")
 17 SEARCH_DIR("/usr/lib/pymodules/")
 18 SEARCH_DIR("/usr/lib/mate-utils/")
 19 SEARCH_DIR("/usr/lib/atril/")
 20 SEARCH_DIR("/usr/lib/python2.6/")
 21 SEARCH_DIR("/usr/lib/gpt/")
 22 SEARCH_DIR("/usr/lib/lognorm/")
 23 SEARCH_DIR("/usr/lib/arm-none-eabi/")
 24 SEARCH_DIR("/usr/lib/tc/")
 25 SEARCH_DIR("/usr/lib/vlc/")
 26 SEARCH_DIR("/usr/lib/udisks2/")
 27 SEARCH_DIR("/usr/lib/python2.7/")
 28 SEARCH_DIR("/usr/lib/locale/")
 29 SEARCH_DIR("/usr/lib/mate-applets/")
 30 SEARCH_DIR("/usr/lib/dconf/")
 31 SEARCH_DIR("/usr/lib/crash/")
 32 SEARCH_DIR("/usr/lib/wine/")
 33 SEARCH_DIR("/usr/lib/x86_64-linux-gnu/")
 34 SEARCH_DIR("/usr/lib/ghc/")
 35 SEARCH_DIR("/usr/lib/mime/")
 36 SEARCH_DIR("/usr/lib/man-db/")
 37 SEARCH_DIR("/usr/lib/glib-networking/")
 38 SEARCH_DIR("/usr/lib/locate/")
 39 SEARCH_DIR("/usr/lib/openssh/")
 40 SEARCH_DIR("/usr/lib/gvfs/")
 41 SEARCH_DIR("/usr/lib/mozilla/")
 42 SEARCH_DIR("/usr/lib/clang/")
 43 SEARCH_DIR("/usr/lib/gnome-keyring/")
 44 SEARCH_DIR("/usr/lib/gtags/")
 45 SEARCH_DIR("/usr/lib/iceweasel/")
 46 SEARCH_DIR("/usr/lib/libreoffice/")
 47 SEARCH_DIR("/usr/lib/utempter/")
 48 SEARCH_DIR("/usr/lib/os-prober/")
 49 SEARCH_DIR("/usr/lib/ghostscript/")
 50 SEARCH_DIR("/usr/lib/lazarus/")
 51 SEARCH_DIR("/usr/lib/node_modules/")
 52 SEARCH_DIR("/usr/lib/klibc/")
 53 SEARCH_DIR("/usr/lib/mate-panel/")
 54 SEARCH_DIR("/usr/lib/gnome-shell/")
 55 SEARCH_DIR("/usr/lib/systemd/")
 56 SEARCH_DIR("/usr/lib/grub/")
 57 SEARCH_DIR("/usr/lib/ssl/")
 58 SEARCH_DIR("/usr/lib/at-spi2-core/")
 59 SEARCH_DIR("/usr/lib/gjs/")
 60 SEARCH_DIR("/usr/lib/accountsservice/")
 61 SEARCH_DIR("/usr/lib/odbc/")
 62 SEARCH_DIR("/usr/lib/mpage/")
 63 SEARCH_DIR("/usr/lib/menu-cache/")
 64 SEARCH_DIR("/usr/lib/gcc/")
 65 SEARCH_DIR("/usr/lib/p7zip/")
 66 SEARCH_DIR("/usr/lib/gcj/")
 67 SEARCH_DIR("/usr/lib/X11/")
 68 SEARCH_DIR("/usr/lib/python3.4/")
 69 SEARCH_DIR("/usr/lib/emacsen-common/")
 70 SEARCH_DIR("/usr/lib/gnupg2/")
 71 SEARCH_DIR("/usr/lib/jvm-exports/")
 72 SEARCH_DIR("/usr/lib/samba/")
 73 SEARCH_DIR("/usr/lib/groff/")
 74 SEARCH_DIR("/usr/lib/eject/")
 75 SEARCH_DIR("/usr/lib/policykit-1/")
 76 SEARCH_DIR("/usr/lib/os-probes/")
 77 SEARCH_DIR("/usr/lib/cdbs/")
 78 SEARCH_DIR("/usr/lib/traceevent_4.9/")
 79 SEARCH_DIR("/usr/lib/grub-legacy/")
 80 SEARCH_DIR("/usr/lib/pulse-10.0/")
 81 SEARCH_DIR("/usr/lib/mc/")
 82 SEARCH_DIR("/usr/lib/ldscripts/")
 83 SEARCH_DIR("/usr/lib/kexec-tools/")
 84 SEARCH_DIR("/usr/lib/apt/")
 85 SEARCH_DIR("/usr/lib/llvm-3.6/")
 86 SEARCH_DIR("/usr/lib/fpc/")
 87 SEARCH_DIR("/usr/lib/cli/")
 88 SEARCH_DIR("/usr/lib/lp_solve/")
 89 SEARCH_DIR("/usr/lib/xine/")
 90 SEARCH_DIR("/usr/lib/xorg/")
 91 SEARCH_DIR("/usr/lib/mutter/")
 92 SEARCH_DIR("/usr/lib/gettext/")
 93 SEARCH_DIR("/usr/lib/lmbench/")
 94 SEARCH_DIR("/usr/lib/libvte-2.91-0/")
 95 SEARCH_DIR("/usr/lib/emacs/")
 96 SEARCH_DIR("/usr/lib/gnome-settings-daemon-3.0/")
 97 SEARCH_DIR("/usr/lib/evolution-data-server/")
 98 SEARCH_DIR("/usr/lib/rtkit/")
 99 SEARCH_DIR("/usr/lib/ccache/")
100 SEARCH_DIR("/usr/lib/rsyslog/")
101 SEARCH_DIR("/usr/lib/gold-ld/")
102 SEARCH_DIR("/usr/lib/evolution/")
103 SEARCH_DIR("/usr/lib/python3.5/")
104 SEARCH_DIR("/usr/lib/libpeas-1.0/")
105 SEARCH_DIR("/usr/lib/git-core/")
106 SEARCH_DIR("/usr/lib/linux-kbuild-4.8/")
107 SEARCH_DIR("/usr/lib/ispell/")
108 SEARCH_DIR("/usr/lib/mono/")
109 SEARCH_DIR("/usr/lib/perf_4.9-core/")
110 SEARCH_DIR("/usr/lib/spice-protocol/")
111 SEARCH_DIR("/usr/lib/debug/")
112 SEARCH_DIR("/usr/lib/sudo/")
113 SEARCH_DIR("/usr/lib/rustlib/")
114 SEARCH_DIR("/usr/lib/stardict/")
115 SEARCH_DIR("/usr/lib/lapack/")
116 SEARCH_DIR("/usr/lib/upower/")
117 SEARCH_DIR("/usr/lib/coreutils/")
118 SEARCH_DIR("/usr/lib/tcltk/")
119 SEARCH_DIR("/usr/lib/linux-kbuild-4.9/")
120 SEARCH_DIR("/usr/lib/VBoxGuestAdditions/")
121 SEARCH_DIR("/usr/lib/bcc/")
122 SEARCH_DIR("/usr/lib/girepository-1.0/")
123 SEARCH_DIR("/usr/lib/sysctl.d/")
124 SEARCH_DIR("/usr/lib/cgi-bin/")
125 SEARCH_DIR("/usr/lib/qemu/")
126 SEARCH_DIR("/usr/lib/pyshared/")
127 SEARCH_DIR("/usr/lib/dpkg/")
128 SEARCH_DIR("/usr/lib/mate-screensaver/")
129 SEARCH_DIR("/usr/lib/compat-ld/")
130 SEARCH_DIR("/usr/lib/engrampa/")
131 SEARCH_DIR("/usr/lib/valgrind/")
132 SEARCH_DIR("/usr/lib/aspell/")
133 SEARCH_DIR("/usr/lib/llvm-3.8/")
134 SEARCH_DIR("/usr/lib/gnupg/")
135 SEARCH_DIR("/usr/lib/pluma/")
136 SEARCH_DIR("/usr/lib/tasksel/")
137 SEARCH_DIR("/usr/lib/security/")
138 SEARCH_DIR("/usr/lib/ogdi/")
139 SEARCH_DIR("/usr/lib/texinfo/")
140 SEARCH_DIR("/usr/lib/linux-boot-probes/")
141 SEARCH_DIR("/usr/lib/mate-power-manager/")
142 SEARCH_DIR("/usr/lib/gnome-settings-daemon/")
143 SEARCH_DIR("/usr/lib/sasl2/")
144 SEARCH_DIR("/usr/lib/tmpfiles.d/")
145 SEARCH_DIR("/usr/lib/qt/")
146 SEARCH_DIR("/usr/lib/binfmt.d/")
147 SEARCH_DIR("/usr/lib/bonobo/")
148 SEARCH_DIR("/usr/lib/w3m/")
149 SEARCH_DIR("/usr/lib/xserver-xorg-video-intel/")
150 SEARCH_DIR("/usr/lib/telepathy/")
151 SEARCH_DIR("/usr/lib/nautilus/")
152 SEARCH_DIR("/usr/lib/GraphicsMagick-1.3.23/")
153 SEARCH_DIR("/usr/lib/nodejs/")
154 SEARCH_DIR("/usr/lib/dkms/")
155 SEARCH_DIR("/usr/lib/perl5/")
156 SEARCH_DIR("/usr/lib/xscreensaver/")
157 SEARCH_DIR("/usr/lib/binfmt-support/")
158 SEARCH_DIR("/usr/lib/colord/")
159 SEARCH_DIR("/usr/lib/jvm/")
160 SEARCH_DIR("/usr/lib/tar/")
161 SEARCH_DIR("/usr/lib/policykit-1-gnome/")
162 SEARCH_DIR("/usr/lib/mate-notification-daemon/")
163 SEARCH_DIR("/usr/lib/gcc/x86_64-linux-gnu/5/32/")
164 SEARCH_DIR("/usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/")
165 SEARCH_DIR("/usr/local/lib/fpc/3.1.1/")
166 INPUT(
167 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/si_prc.o
168 h.o
169 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/system.o
170 f1.o
171 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl-console/crt.o
172 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/baseunix.o
173 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/unix.o
174 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/termio.o
175 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/unixtype.o
176 /usr/local/lib/fpc/3.1.1/units/i386-linux/rtl/unixutil.o
177 )
178 SECTIONS
179 {
180   .fpcdata           :
181   {
182     KEEP (*(.fpc .fpc.n_version .fpc.n_links))
183   }
184   .threadvar : { *(.threadvar .threadvar.* .gnu.linkonce.tv.*) }
185 }
186 INSERT AFTER .data;

link.res L167 ~ 176 連結了不少 .o 檔案。

來看看 benchmark Pascal Free Pascal programs versus Java, 還真的不怎麼樣。

ref:

2017年9月9日 星期六

[開箱不敗家] 這不是 brompton


  • 20170815 訂購於淘寶, 3631 rmb = 16600 nt, 18kg, 國際運費 14*18 rmb = 1160 nt (管家集運), 總計費用 16600+1160 = 17760nt。
  • 20170820 管家集運發台灣
  • 20170824 收到
订单号: 46640506133669095513单车配件②店
3688.00
3577.36
1
投诉卖家
3681.12
3631.00
(含运费:¥14.00)
等待买家付款
102.00
89.76
1
投诉卖家

怎麼把這個大東西運回來讓我商透腦筋, 原本用的集貨會改用體積計算, 費用太貴, 在買賣討論區上, 我找到了管家集運, 根據重量計費, 18kg * 14rmb = 1160nt。

我喜歡單車上有土除、貨架、腳架, 這都是我覺得在單車上要有的必備品, 但我目前用有的單車很少全部符合, carryme 勉強符合這些條件。這次購買的這台, 則沒有腳架, 停車時會很不方便, 我知道可以用折疊方式來停車, 但折折疊疊實在煩人, 又我放置了馬鞍袋的時候又該怎麼辦?

本來想購買綠色, 最後挑了還不錯看的米黃色。

嚴格來說, 這台單車不能算是縱向折疊, 前輪部份依舊是橫向折疊, 為了良好的折疊性, 也只能這樣取捨, 這也是我猶豫不決的部份, 所以一直沒下手買 brompton, 二手 brompton 也不便宜, 所以最後購入此車。

剛收到車時, 輪胎是沒有氣的, 這是為了運輸的安全, 帶上飛機就得要這麼做, 將輪胎放氣, 所以一開始得先打飽氣才行。

這不是什麼問題, 對於一個單車愛好者來說, 有個打氣筒並不是什麼奇怪的事情, 氣很快就打飽, 馬上來試車。

嗯! 16 吋輪胎果然騎起來要稍微適應一下, 雖然不像 carryme 那樣, 但和一般單車比起來也是有所不同, 操控性差了點, 能用 brompton 騎山路的人真是好腳力。

規格:

车身折叠参数:长600MM 高600MM 厚26MM
车体净重:12.5KG左右,带纸箱包装毛重15KG
纸箱包装参数:长71CM高64CM宽:35CM



單車有 3 段變速, 老實說功用不大, 這台單車的定位是和大眾運輸系統一起使用, 和 carryme 一樣, 不是 moulton tsr, birdy 的運動風設定, 我沒那麼好的腿力可以靠它騎長距離或是山路, 至少要給我 8 段變速我才能這麼做。

易行輪很好推, 折疊時推起來很順手, 和 birdy 的手感不同, birdy 的後貨架折疊後太不好推了。

這台不是 brompton, 就叫它「小黃」好了。

brompton 據聞專利過期, 開始有車廠在製作這樣折疊機構的單車, 有的是鋁的材質, 但我想要買鐵的版本。

哎呀! 台灣就有了《【單車倉庫 MiNi M3 變速縱向摺疊車】3sixty Mini m3摺疊車 媲美英國小布BROMPTON摺疊體積輕巧》(15900) 我幹麻還去淘寶買, 耍笨了。


早知道就不用這樣折騰了, 價錢比較貴又要等上好幾天, 又要擔心有沒被摔壞, 看了一些評價, 有的單車被摔到了, 貨架歪了, 我這台運氣好, 看起來沒什麼異狀。疑! 加上後貨架 (1500) 和豬鼻子 (590) 之後, 就比我從淘寶買還貴一點。



體積輕巧 縱向小折 「折疊車」 3sixty mini
型號
單車倉庫 MiNi M3 變速縱向摺疊車
車架
鉻鉬鋼Cr-mo
車把
鋁合金把手
變速手把
Sturmey ArcherSUNRACE  (內三速)
鏈條
KMC 防鏽 鏈條
大齒盤
 大盤齒數47T
車圈
6061鋁合金+T6熱處理 雙層輪圈
輪胎
16 外胎 
煞車
鋁合金 C
握把
牛皮舒適握把
花鼓
前鋁合金陽極花鼓  Sturmey ArcherSUNRACE內變速花鼓
踏板
摺疊式腳踏
重量
約11.5公斤  


(金點單車) LaBici 縱向摺疊車 米蘭青色 / 小布 Brompton Birdy (12800), 這是鋁合金車架的版本。

「小黃」也是鐵的材質, 車身沒有任何字樣, 這樣乾乾淨淨也不錯, 嗯! 應該是有特殊原因吧! 騎起來不算好騎, 但也不差, 買便當絕對夠用, 騎長程可能會有點累人。

這款車可能會威脅到 ori, 我曾經有想過買 ori, 但現在有了這台後, 已經不會想買 ori 了, 不過我認為 ori 的騎乘性能還是好過這台的。

試騎一陣子後發現車子後方會有怪聲, 不知道是什麼原因, 出現後過一下子又會消失, 好在這台車設定為短距離騎乘, 可以暫時忽略, 但螺絲掉下來就不能忽略了。

掉下來的螺絲是後貨架的螺絲, 總共有 4 個, 果然都沒鎖緊, 鎖緊後就好多了, 由於折疊會和後貨架有關, 這裡沒鎖緊折疊起來還蠻危險的。

小黃與玻弟
這台車只要是折疊單車愛好者應該都會知道, 沒什麼好介紹, 特規零件比較麻煩, 例如花鼓的部份, sunrace 的內變也還可以, 暫時沒有想做什麼改裝, 3 段變速我得用上最輕的那段, 所以幾乎只有一段, 頂多改成無變速吧!



LM 區是一個很好的騎車地點, 就到那裡試車吧! 小黃的鏈條出了點狀況, 脫離一個齒輪, 沒問題, 把鏈條掛回該齒輪即可。

短程看來沒什麼問題, 可以和大眾交通工具接駁是我最需要的部份。

至於豬鼻子 (就是用來掛前菜籃的一個裝置) 還沒裝上, 暫時沒有什麼心得。

ref:
捷世樂® 單車休閒 ~ BROMPTON 特殊色【灰色地帶】 ,經銷商試乘車,試乘亮相

2017年9月1日 星期五

function reentrant, thread-safe, memory ordering (memory barrier)

the 1st edition: 20130301
the 2nd edition: 20151001
the 3rd edition: 20170727
這篇是個雜記, 紀錄這三個惱人的東西還有一些自己的問題。

http://tw.myblog.yahoo.com/blue-comic/article?mid=253&prev=257&l=f&fid=26
http://blog.xuite.net/jackie.xie/bluelove/46644355

在寫怎麼樣的程式時, 需要考慮 reentrant?
在寫怎麼樣的程式時, 需要考慮 thread-safe?

在 multi-thread 程式中, 需要的是 reentrant 還是 thread-safe?

Fast Atomic Counters With the x86 LOCK Prefix:
http://www.codemaestro.com/reviews/8

問題很混亂, 不過看了 pthread 多緒程式設計 (p237), 有了比較清楚的概念:

簡單提一下 (詳細請參閱該書籍):

thread safe: 使用 mutex 來保護 global data, 而 data 不一定是變數, 可能是檔案, 可能是某個週邊。由於用了 lock, 很有可能會有 dead lock 的問題。

reentrant function: 不可使用 static, global data, 一定可以正常執行, 也不會有 dead lock 的問題。

那 reentrant function 裡頭用 mutex 保護共用資源算 thread safe 嗎? 算, 不過那就不是 reentrant function 了, 請參考 malloc() is non-reentrant but thread-safe? [duplicate] 提到 reentrant, thread-safe 是如何的不同?

malloc 是 thread safe, 但不是 reentrant, 該怎麼解釋呢? reentrant 和 thread 的行為有點微妙的不同 (感謝 tg 的朋友解惑):

list 1. thread
1 thread:
2 void thread_1()
3 {
4   malloc()
5   {
6     lock();
7 
8     set_list();
9 
10     unlock();
11   }
12 }
 
13 void thread_2()
14 {
15   malloc()
16   {
17     lock();
18 
19     set_list();
20 
21    unlock();
    }
   }

thread_1() 執行到 set_list() 時, 換 thread_2 執行, list 1 L17 會卡住 thread_2, 等到執行權切回 list 1 L8 後, 執行 L10 之後, unlock, 若這時候切回 thread_2, thread_2 得以繼續執行。

reentrant 會和中斷扯上關係:

list 2. reentrant
01 void func_1()
02 {
03   malloc()
04   {
05     lock();
06 
07     set_list();
08 
09     unlock();
10   }
11 }
 
12 void isr_1()
13 {
14   malloc()
15   {
16     lock();
17 
18     set_list();
19 
20     unlock();
     }
   }

func_1 執行到 set_list() 時, 中斷發動了, 改為執行 isr_1(), isr_1 卡在 list 2 L16, 但程式再也回不到 list 2 L7 那行了, 在中斷 isr 中, 沒有做完是切不回去 func_1 的, 這是和 thread 最不一樣的行為, 所以會一直卡在 list 2 16 那行。

所以才說, malloc 是 thread safe, 但不是 reentrant。

Reentrancy and Thread-Safety
Hence, a thread-safe function is always reentrant, but a reentrant function is not always thread-safe.

Linux环境编程:从应用到内核 (Linux/Unix技术丛书) 0.4.5 可重入函数

可重入函数一定是线程安全的, 而线程安全函数则不一定是可重入函数。

以上兩個說法完全相反, 該聽誰的呢?

我自己是贊同《Linux 环境编程》的說法。但不用太拘泥名詞解釋, 了解本質上的不同是比較重要的。

reentrant.cpp
 1 #include <signal.h>
 2 #include <pthread.h>
 3 
 4 #include <chrono>
 5 #include <iostream>
 6 using namespace std;
 7 using namespace std::chrono;
 8 
 9 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
10 
11 volatile int i=5;
12 
13 void thread_safe_func()
14 {
15   pthread_mutex_lock(&mutex);
16 
17   for (int i=0 ; i < 200000 ; ++i)
18     for (int i=0 ; i < 10000 ; ++i)
19     {
20     }
21   i = 1;
22 
23   pthread_mutex_unlock(&mutex);
24 }
25 
26 void sig_handle(int sig)
27 {
28   thread_safe_func();
29 }
30 
31 int main(int argc, char *argv[])
32 {
33   signal(SIGINT, sig_handle);
34   thread_safe_func();
35   #if 0
36   time_point<steady_clock> tp1 = steady_clock::now();
37 
38 
39   time_point<steady_clock> tp2 = steady_clock::now();
40 
41   typedef duration<unsigned long long, ratio<1,1000000>> unit;
42   unit d = duration_cast<unit>(tp2 - tp1);
43   cout << d.count() << endl;
44   #endif
45   return 0;
46 }

reentrant.cpp 是我模仿 malloc 而來, 在程式執行後, 按下 ctrl+c SIGINT, 這時候用 ps 觀察

ps aux |grep reentrant
descent   7210  0.2  0.0  15232  1640 pts/68   S+   10:12   0:01 ./reentrant

PROCESS STATE CODES
  Here are the different values that the s, stat and state output specifiers 
  (header "STAT" or "S") will display to describe the state of a process:

          D    uninterruptible sleep (usually IO)
          R    running or runnable (on run queue)
          S    interruptible sleep (waiting for an event to complete)
          T    stopped, either by a job control signal or because it is being traced
          W    paging (not valid since the 2.6.xx kernel)
          X    dead (should never be seen)
          Z    defunct ("zombie") process, terminated but not reaped by its parent

  For BSD formats and when the stat keyword is used, additional characters may be displayed:

          <    high-priority (not nice to other users)
          N    low-priority (nice to other users)
          L    has pages locked into memory (for real-time and custom IO)
          s    is a session leader
          l    is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
          +    is in the foreground process group

處在 interruptible sleep (waiting for an event to complete), 程式無法正常結束, 應該是卡在 L15。

reentrant.cpp L17, L18 的 for loop 單純用來 delay, 在我系統上, 大概是 3 秒, 為的是讓 SIGINT 有時間可以在

15   pthread_mutex_lock(&mutex);
            ...
23   pthread_mutex_unlock(&mutex);

這中間的時候送出。

而程式也無法正常結束。

ref What does the “interruptible sleep” state indicate?


ref:



再來是 memory ordering (memory barrier) 這問題:

我也被這問題困惑很久, 在 os 下寫應用程式, 幾乎沒用過這種指令, 有需要在 os 下的應用程式使用這些指令嗎? 還是被 os api 給包裝起來了呢?

這是 linux 在 x86 下使用的 memory barrier 指令。
#define mb() asm volatile("mfence":::"memory")
#define rmb() asm volatile("lfence":::"memory")
#define wmb() asm volatile("sfence" ::: "memory")

arm cortex m3 memory barrier 指令: isb, dsb

Binary Hacks - 駭客秘傳技巧一百招 #94 在談這個, 看完就清楚了, 可是我不知道怎麼寫程式測試這個情形。

不過這樣的話, 在 os 下寫應用程式也會遇到這問題才是, 可是卻沒看過在 os 下的 c 應用程式用上這種指令。

multi-thread 程式要突破兩關:
  1. lock 機制 (使用 test-and-set 硬體指令實作)
  2. memory ordering (使用 memory barrier 指令)
才有正確的結果。

1 通常由 os api 提供 (x86 可用 bts/xchg 實作, arm cortex M3 可用 ldrex/strex 來實作)。
2 我就沒看過在 os 下的應用程式要怎麼用, 只看過在 driver 階段有使用過。這篇提到 memory barrier pthread 已經實作在裡頭了。

thread 程式的共享變數還需要用 volatile 來宣告, 僅僅加上 lock 是不夠的。
ref:
http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=1920275
http://www.parallellabs.com/2010/12/04/why-should-we-be-care-of-volatile-keyword-in-multithreaded-applications/

ref memory barrier (ptt damody provides):

下一個類似的問題是:
mutex/semaphore and spin lock, 你知道的, 我要的不是教科書的解釋, 我想要實作這些東西出來, 能實作出來就真能代表懂了。

目前我在 arm cortex-m3 使用 ldrex/strex 實作出 spin lock。

Linux内核同步机制之(一):原子操作
這篇做了很好的解釋。

Linux内核同步机制之(三):memory barrier

蜗窝科技出版的文章, 質/量都很好。

2017年8月25日 星期五

[books] 哥德尔、艾舍尔、巴赫 - 集异璧之大成

20160219 訂購於淘寶, 20160306 收到
原文名稱是 Gödel, Escher, Bach: an Eternal Golden Braid, 看不懂書名吧, 就算是中文書名也一樣摸不清這本書是幹嘛用的吧, 比 Code: The Hidden Language of Computer Hardware and Software 還奇怪吧!

你很難念出這本書的名字吧, 直接提 GEB 就可以了, 簡單、輕鬆、不明瞭; 中文則是簡稱《集异璧》。

這本書中國之前有部份的翻譯《GEB:一条永恒的金带》, 由四川人民出版社出版, 沒全翻譯也能出書, 真奇怪, 更奇怪的是還有兩間出版社來出版。不過這本就是全譯本了, 可以放心的閱讀。

忘記在哪裡看到這本書的推薦, 大概是那種「你一定要讀的十本書」之類的文章。通常裡頭介紹的書當然不會是一定要讀的書, 沒有哪本書是一定要讀的, 找自己讀得下去、讀得來、讀得快樂的才是對自己好的。

據說這是本奇書, 有多奇呢? 看到書名你有沒有莫測高深的感覺, 這是在寫什麼阿?

這本書介紹了數理邏輯、可計算理論、人工智慧 (最近很紅的電腦 AlphaGo 和南韓棋士下圍棋的那個)。

作者 Douglas Richard Hofstadter 有個中文名字 - 侯世达, 很重視這本書的翻譯, 不管是翻譯成哪國語言, 他都要插上一手, 德、法、西班牙的翻譯本是這樣, 簡體中文譯本也是, 他和這本書的簡體中文翻譯教授有了一些對翻譯上的對話, 所以這本書被翻譯成了中國味很濃厚的翻譯書了, 這也是作者本身想要的翻譯方式。

葉落天落葉、A man, a plan, a canal: Panama, 並不是只有文學上有回文 (ref: http://www.lungteng.com.tw/LungTengNet/HtmlMemberArea/publish/Newpaper/012/english/p029-031.pdf), 音樂也是有回文這種東西, 叫作「螃蟹卡農」

螃蟹卡農:

A man, a plan, a canal: Panama
這句話如果翻成中文, 一定會失去其回文的意義。
翻譯之難一

speak of the devil 是 speak of the devil and the devil appears. 的壓縮。難怪語言真的不好學了。

應該翻成:
說到鬼,鬼就來。
還是
說曹操, 曹操就到。

翻譯之難二
作者希望的是《說曹操, 曹操就到。》這樣的翻譯, 聽說這叫作移 (迻) 譯。
目前就看這麼多了, 希望有吸引你去看這本書。

侯世达谈geb的中译

1985年,我在完全偶然的情况下得知有人准备把geb译成中文。我在密歇根大学的同事和友人亚瑟•伯克斯(Arthur Burks)刚从仍然沿用Peking拼法的Beijing大学回来,他无意中提到计算机系的吴允曾和马希文两位教授正在主持这项工作。

我惊喜交加,但不无担忧,因为之前在geb被译成西班牙语和德语的过程中,我都向译者提供了自己做的注解,这些东西花了我几百个小时,但最后不是没有到达译者手里,就是被他们直接忽视了。于是前者付梓之后很快泯然于世了,而后者粗糙乏味的译稿只能算勉强及格,所幸后来得到geb的荷兰语译者罗纳德•容克斯(Ronald Jonkers)等人的大力润色。

我首先想到的当然是尽快把注解送到中译者手里,但很快一个新的想法在脑海中闪现。戴维•莫泽(David Moser,geb的法译者之一。这个译本是侯世达最欣赏的。)当时正在苦学中文,准备去中国呆一段时间,何不让他去走一遭?戴维、罗纳德和我曾在巴黎一起探讨过翻译geb的策略,戴维的翻译哲学与我的不谋而合。

在当时的学界,网络还不是主要的沟通渠道,于是我给吴教授和马教授去了封信。很快,吴教授的亲笔回信就到了,他的英语非常棒。吴教授证实了一个我担忧已久的问题,他的翻译队伍中没有英语母语人士,但好在工作才开始不久,他非常欢迎戴维加入进来。吴教授还提到他计划亲自来美国一趟,希望与我见上一面。我高兴地回信邀请他来安娜堡小住几天。

于是1986年春天,戴维出发去了北京。在那里,他见到了吴教授和马教授,他们已经组织起一支高水平的翻译队伍,但实质性工作还未展开。他们向戴维介绍了队伍中两位关键成员:严勇,一位头脑敏捷,富有机智的计算机专业研究生;刘皓明,一位文学系研究生,同时也是出色的艺术家,推荐他的正是严勇,因为刘皓明善于用别出心裁的方式组织中文。三人很快成为好友和密切的工作伙伴。

就在戴维抵达北京几天后,吴教授也来到了美国。为了让他在底特律机场认出我,我在一块牌子上写了“吴允曾——欢迎你!”。我们没费什么劲就找到了对方,然后一起去了我在安娜堡的家。我们和卡罗尔以及梅拉尼•米切尔一起吃了意大利风味的晚餐,通心粉尤其对吴教授的胃口,因为他的牙都快掉光了。他发现我和梅拉尼会说一些中文,于是就用中文问了我们几个问题,可惜我们答得都不太好。从此,我们只用英语交流。

吴教授的英语相当不错,虽然口音很重,对此我们都很好奇。他解释说,自己小时候上学时都是英语授课,自己还有个英语名字“安德鲁”。虽然他让我们这样称呼他,但我们总觉得不自然,于是仍然称他“吴教授”。

为了让吴教授对geb中的一些疑难段落有更深的了解,我请来法译者之一的鲍勃•弗兰奇(Bob French)一起吃饭,选的当然还是一家意大利餐馆。我们谈到书中被称为“螃蟹卡农”的一段对话。“螃蟹卡农”原来是巴赫《音乐的奉献》中的一小段,它由两把小提琴演奏,但乐曲正向或反向演奏的效果都是一样的,只是两把小提琴或者说两个声部的角色互换了。因为据说螃蟹是逆行的(实际是横行),于是这类乐曲就被称为“螃蟹卡农”。

我刚描述了“螃蟹卡农”的特点,吴教授马上指出它很像回文,他举了“落叶天落叶”的例子。于是我们试着把它翻成英文:leaves fall season fall leaves,但fall既可以表示落下,也能指秋天,而leaves既有树叶的意思,也可表示离开,于是我们得到一句英语的回文:fall leaves as soon as leaves fall.

然后,我们也举了一句经典的英语回文,让吴教授把它翻成中文:a man, a plan, a canal, Panama!但吴教授脸上却显出疑惑之色,他认为这根本不是回文。原来,他是一个个单词来看这句话的!

最后,我们一致同意,由于两种语言在构成形式上的根本差异,想要把这句话翻成中文回文是不可能的。不过我提出,这句话的意义不在于它的内容,而在于形式上的对称性,如果硬要把它的内容翻译出来,就完全失去了它的存在意义,就像“没汽的汽水”。而一句形式上对称的中文回文,即使意思与之无关,在某种程度上却反而是“忠实”翻译。

正当我、鲍勃和吴教授在安娜堡一边吃着通心粉,一边谈笑风生的时候,半个地球之外也在进行一场类似的谈话。戴维刚到北京就一头扎进了已经完成的那部分geb译稿中。在一篇名为“the magnificrab, indeed”(与巴赫的magnificat in D谐音)的对话中,他发现“speak of the devil”被译作“说鬼,就来鬼!”戴维问刘皓明等人:“这句话是否中国谚语?”
他得到的回答是:“不,但读者很容易猜出它的意思。”

戴维又问:“那么有什么中文谚语能表达speak of the devil的意思吗?”

他们说:“当然,说到曹操曹操就到。”但他们随即表示,曹操属于中国文化,只有中国作者会用这个谚语。因为读者知道geb的作者是美国人,他们会无法接受的,美国人怎么可能知道曹操?

戴维顿时无语,想了一会儿他说:“但读者显然知道侯世达的原书不是用中文写的,他们知道这是翻译。侯世达想要的是把geb翻译得语句通顺,并且让中国读者感到自然。实际上,他正是要让读者感觉geb是用中文写的。”

对我和戴维来说,这是显而易见的。但严勇和刘皓明却表示强烈反对:“如果按照你的要求,用纯粹中文的风格来重建这本书,读者就会认为它不再是侯世达的作品了。”

后来的情况大家也知道了,戴维最终说服了严勇和刘皓明,以及翻译队伍中其他的两名成员王培和郭维德。在翻译“螃蟹卡农”时,我们收集了许多能表示不同意思的中文词组,比如“周末愉快”既是对话开始时的问候,又被用在结尾表示道别。整个团队完全接受了这种跨文化的翻译方式,有一天刘皓明甚至对戴维表示,他们原来的“忠实”翻译就像没有放辣酱的四川菜一样无味。虽然刘皓明没有听说过“没有汽的汽水”这句美国谚语,但他无意中又做了一次跨文化翻译。

很遗憾,吴教授于1987年在北京因心脏病去世,享年69岁。他不仅是翻译计划的发起人,还在整个过程中听取了各种意见。整个翻译团队忠实执行了他的意见,他们的成果离不开这位富有冒险精神的老人,我想吴教授自己也会这样认为的。

ref:
What is the single most influential book every programmer should read?

2017年8月18日 星期五

樹莓派 2 透過 linux sys 設定 gpio

利用 linux sys 檔案系統來設定 gpio 很簡單, 不簡單的是 gpio 編號是多少呢? 我找了好久終於找到樹莓派 2 的 gpio pin 圖。

發現可以用 gpio pin 17, 27 來測試。

樹莓派 2 gpio pin

cd /sys/class/gpio
echo 27 > export
echo out > gpio27/direction
echo 1 > gpio27/value

cd /sys/class/gpio
echo 17 > export
echo out > gpio17/direction
echo 1 > gpio17/value

由於我沒有接上 led, 所以透過 LA 來確認有無正確設定這 2 個 gpio pin。



觀察 gpio 編號

mount -t debugfs none /sys/kernel/debug/
cat /sys/kernel/debug/gpio

#!/bin/sh
cd /sys/class/gpio/
echo 17 > export
echo out >  gpio17/direction

echo 27 > export
echo out >  gpio27/direction

while true; do
    echo 1 > /sys/class/gpio/gpio17/value
    echo 0 > /sys/class/gpio/gpio27/value
    #sleep 0.5
    echo 0 > /sys/class/gpio/gpio17/value
    echo 1 > /sys/class/gpio/gpio27/value
    #sleep 0.5
done

LA 抓到的波型

2017年8月11日 星期五

20170805~0806 coscup

coscup 是一年一度的 opensource 大會, 今年有搶到報名, 機會難得, 再次前往參加。



如何搭車依然困擾我, 最後選了比較辛苦的方式, 不知道是不是頭腦不清楚, 下車時, 還把紅色小帽留在車上, 好幾天之後, 才順利取回, 感謝行車人員的辛勞。

台北果然就是車多、人多, 不太習慣, 走路到捷運入口後, 搭乘捷運到科技大樓站, 再走路到台大社會科學院, 有點距離, 好在難不倒我, 就是手上東西多了點。

大概在 08:00 左右到達, 早到了, 工作人員才剛要開始佈置場地, 我就找個地方, 好好休息一下, 有點累!

08:45 報到後, 先去名人場, 有張善政董事長、呂秋遠律師、吳聲明建築師、柯文哲市長, 吳聲明的大稻埕、迪化街商圈建築的打造令我讚嘆, 我常覺得台灣的文化意識很低, 大部分人看中的還是錢錢錢, 吳聲明運用本身專業, 打造了和大稻埕、迪化街的空間, 讓附近的人們分享彼此遺忘的古老回憶, 這才是政府應該大力補助的文創才是, 而不是都在賣東西。

柯文哲, 就是那個台北市長, 大家都很熟, 不多說了, 我是帶著拜神的敬意來聽演講的。



再來是 303 的區塊鏈主題, 很多人, 擠不太進去, 這麼火紅的主題, 我應該要來略懂一下, 聽別人的分享是最快的。不過人算不如天算, 這場講者不講區塊鏈, 厄 ... 也沒關係, 就聽聽別的東西也很好。



最近共享單車很紅, 不過這邊只有 YouBike 台北市公共自行車, 我沒有登記的悠遊卡, 只能用信用卡借車, 但我搞了半天在選車時, 系統當機了, 後來就不再給我用信用卡借車了, 第一次使用的感覺很不好, 我又詢問 YouBike 客服, 信用卡客服, 確認有無被扣款, 心情不太好。最後就沒借車了。

隔壁體育館是動漫展, 好想去阿! 時間真的不夠。

下午聽了用 gcc 來最佳化 postgresql 的議程, 原來編譯器還真有特異功能, 只要選項下的好, 就有機會可以得到高效能的執行檔。

簡報: 用 GCC 讓你的 PostgreSQL 噴噴噴

fig 3. dd 3分皮革高跟開口鞋, 1880nt
再來去可汀, 可汀? coscup 有這議程? 當然沒有, 這是娃店, 一年只來一次。

這次主要想看矽膠素體, 可惜還沒到貨, 連展示的版本都沒有, 不過架上有個透明的娃體很吸引我, 目前已經沒有販售了。由於是透明的, 僅僅只有展示的功能, 不太適合拿來一般的打扮。

來尋寶吧! 來這裡幾乎每次都得花大錢才能脫離的, 這次我對一套衣服有興趣, 不過我竟然忘記拍照了, 衣服只適合 M 胸 (3xxx), 所以我就沒出手, 而且價錢也讓我猶豫中 ...

這次運氣還不錯, 似乎沒被什麼配件吸引到 (這算好處嗎?), 當然照例也要欣賞店長的娃娃, 這次店裡真是難得, 沒什麼人, 逛起來比較輕鬆。我仔細的觀察所有服飾配件, 最終被 fig 3 的 皮革高跟開口鞋吸引。

fig 3 可不是那個正妹的美腿, 是 3 分 DD 娃, 那雙鞋我一樣看了好幾遍, 猶豫不決, 過了幾分鐘後, 拿去店長那裡試穿, 當然是店長的娃, 看來還不錯, 就它了。

果然還是要帶點東西回去才有滿足感。晚上到鶯歌借宿 R 君家, 滿滿的火力展示, 感謝招待。

第一天實在太累了, 第二天醒來到會場時已經 11:00, 我想聽的 rust 議程已經都結束了, 趕緊去聽 BSDMIZER: a framework to improve FreeBSD continuously, 真的長見識, 連編譯這個動作都可以加入機器覺習, 讓編譯器編出效能更好的程式碼, 嚇死寶寶了。

Long-term Maintenance Model of Embedded Industrial Linux Distribution 議程則是提供了在工業控制上使用 linux 的經驗, 怎麼選定一個長期支援的 kernel 版本, 通常是以 10 年為計算單位, 講者似乎在一個很棒的 kernel team, 有這樣的能力完成這些工作。
再來就是 emcas 議程, 是 tg 上的朋友開講, fatfingererr, coldnew 都展示了 emcas 強大的能力, 不過我不知道怎麼才能學到他們那樣隨意的使用 emacs, 現在用 emacs 打這篇文章已經是我使用 emcas 的極限了, 無法像他們那樣, 這麼流利的使用。

fatfingererr:
開發連續技 - Auto-Complete 與 yasnippet 的結合應用 by fatfingererr

Yen-Chin Lee:

  1. 一個 org file: https://github.com/coldnew/COSCUP2017_org-mode/blob/master/slide.org
  2. 2013 年的投影片在這: http://coldnew.github.io/COSCUP2013_org-mode/slide.html

這次的下午茶點心還蠻多的, 之前都搶不到, 我找了個地方坐下來, 慢慢享用這些美食。

fig 5. 洋娃娃輓歌
時間差不多了, 我得趕緊離開會場, 趕去參觀一個「洋娃娃輓歌」的展覽, 由 Zihling 和 Mangasick 主辦, 地點在公館和古亭捷運中間, 但我走錯了, 多花了一點時間才到, 是這裡嗎? 我看著那個門, 突然有位水手服美少女走了出來, 沒有圖, 別問了, 我也很想留下一張照片的。我嚇傻了, 竟然在真實世界看到水手服美少女, 後來得知是店員。

再回到那個門, 勇敢的打開它, 進去了, 如果開到隔壁的門, 那就是非法闖入民宅。

Mangasick
是一個很特別的地方, 算是獨立書店。進的是日版的一些很特殊主題的漫畫, 可能會嚇壞人的那種主題, 看起來很詭異和情色有關。目前剛好有個「洋娃娃輓歌」的展覽, 是 Zihling 的插畫作品, fig 5 雖然是一個 bjd, 但這展覽其實是插畫, 和娃娃相關的主題。

我買了千之刃展覽手冊 (280), 本來猶豫不絕, 但看到有千之刃的簽名之後就沒任何猶豫了, 另外買了一本國內插畫家的畫冊 (350), 鼓勵一下國內的插畫創作, 這不容易, 很辛苦。

再來得去找住宿的地方了。從 airbnb 找到「星盒青年旅館」, 只有床位, 但從 airbnb 付款實在繁瑣, 還要附身份證的圖, 我比較喜歡直接到那裡, 詢問、付款、入住, 簡單多了。從中山捷運 5 號出口出來, 但是我走過頭, 南京西路 288 號我走到 4xx 號, 喵的勒。

櫃台小姐很親切, 也是正妹, 這邊進出需要通過警衛的管制, 有點麻煩, 第一次需要有人來帶, 進入電梯到四樓, 星期日價位 420 nt, 只有床位, 我很喜歡這樣的住宿方式, 台北竟然有這個, 隔壁是寧夏夜市, 剛好解決晚餐問題。買燒烤時有遇到一個正妹, 這是幸運的一天。



睡覺時遇到二重唱, 沒在怕的, 趕緊睡著加入三重唱。

本來想再去「白日夢森林」, 也是娃店, 不過交通不太方便, 最後還是沒去, 時間真的不太夠。