[心得] 用 c++ 來開發 uefi 程式

作者: descent (「雄辯是銀,沉默是金」)   2016-06-25 22:31:44
edk2 並沒有支援用 c++ 來開發 uefi 程式, 真是不敢相信還有這麼原始的開發環境,
竟然不支援 c++。我可是 c++ 愛好者, 不能用自己喜歡的語言開發程式, 感覺很不爽。
c++ 的好處我說過好幾次了 (疑! 我根本沒說過!!), c 我也是可以寫的, 為什麼堅持用
c++ 呢? 還真的說不上原因, 大概是網路上很多的討論都對 c++ 很不好, 什麼 XX 比不
上 C, YY 比不上 JAVA, 這些言論更讓我對 c++ 抱不平, 決定要多多推廣 c++, 我又不
善嘴炮言詞, 只好用程式碼來證明 c++ 的能耐。
《UEFI原理与程 ( http://goo.gl/GaujHw )》第十章說明如何用 c++ (g++) 來開發
uefi 程式並提供了 GcppPkg 這個範例, 不過很可惜, 這部份書上寫的不夠詳細, 我花費
了不少時間還是搞不定怎麼使用這個範例。
最後我做了和 GcppPkg 類似的事情, 再加上《UEFI原理与程 ( http://goo.gl/GaujHw )
》第十章的說明, 搞出了自己的 c++ 作法。所以我雖然沒搞定書上的 GcppPkg 範例, 但
是書中內容還是幫了我不少。
最困難的是編譯環境, 花了不少時間我才搞定 (沒有搞懂, 是搞定), 找了
edk2/AppPkg/Applications/Main/Main.c 來修改, 這是使用 c 語言 main 的開發方式。
我建立了 edk2/AppPkg/Applications/Main/m.cpp (從
edk2/AppPkg/Applications/Main/Main.c 複製而來), 也複製了一份 m.inf, m.inf 最重
要的是 L27 ~ 42, 把 source code 的檔案填進去, build 就會去編譯這些檔案。
m.inf
1 ## @file
2 # A simple, basic, application showing how the Hello application could be
3 # built using the "Standard C Libraries" from StdLib.
4 #
5 # Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
6 # This program and the accompanying materials
7 # are licensed and made available under the terms and conditions of the
BSD License
8 # which accompanies this distribution. The full text of the license may
be found at
9 # http://opensource.org/licenses/bsd-license.
10 #
11 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED.
13 ##
14
15 [Defines]
16 INF_VERSION = 0x00010006
17 BASE_NAME = m
18 FILE_GUID = 5ea97c46-7491-4dfd-b442-747010f3ce5f
19 MODULE_TYPE = UEFI_APPLICATION
20 VERSION_STRING = 0.1
21 ENTRY_POINT = ShellCEntryLib
22
23 #
24 # VALID_ARCHITECTURES = IA32 X64
25 #
26
27 [Sources]
28 m.cpp
29 bst.cpp
30 #crtbegin.cpp
31 eh.cpp
32 mylist.cpp
33 mymap.cpp
34 myvec.cpp
35 cstring.cpp
36 gdeque.cpp
37 k_stdio.cpp
38 mem.cpp
39 myiostream.cpp
40 mystring.cpp
41 #my_setjmp.c
42 my_setjmp.S
43
46 [Packages]
47 StdLib/StdLib.dec
48 MdePkg/MdePkg.dec
49 ShellPkg/ShellPkg.dec
50
51 [LibraryClasses]
52 LibC
53 LibStdio
54
55 [BuildOptions]
56 #GCC:*_*_X64_CC_FLAGS = -fno-exceptions -fno-rtti -ffreestanding
-nostdlib -nodefaultlibs -std=c++11
57 MSFT:*_*_*_CC_FLAGS =
58
再來是把這個 m.inf 加到 AppPkg.dsc。
AppPkg.dsc.diff
1 [LibraryClasses]
3 #
4 # Entry Point Libraries
5 #
6 @@ -105,6 +106,7 @@
7 ########################################################################
8
9 [Components]
10 AppPkg/Applications/Main/m.inf
以下是測試的 c++ 檔案。cout 和 vector 不是 edk2 提供的, 是移植我那個玩具標準
c++ 程式庫 ( http://goo.gl/xKIag7 )得來的, namespace 是 DS 而不是 std, 書上的
範例是移植 stl 過來, 我既然已經有自己的版本, 玩具歸玩具, 沒道理不用的。
還順便測試一下目前最潮的 lambda 語法。
還有 setjmp/longjmp x64 的版本。
m.cpp
1 #include "myvec.h"
2 #include "myiostream.h"
3 #include "my_setjmp.h"
4 using namespace DS;
5
6 class Obj
7 {
8 public:
9 Obj()
10 {
11 i=10;
12 ::printf("ctor\n");
13 }
14 ~Obj()
15 {
16 ::printf("dtor\n");
17 }
18 private:
19 int i;
20 };
21
22 jmp_buf jbuf;
23
24 int lambda_test(int girls = 3, int boys = 4)
25 {
26 auto totalChild = [](int x, int y) ->int{return x+y;};
27 return totalChild(girls, boys);
28 }
29
30 int main (IN int Argc, IN char **Argv)
31 {
32 Obj obj;
33
34 int total = lambda_test();
35 cout << "total: " << total << endl;
36
37 vector<int> vec_i;
38
39 vec_i.push_back(1);
40 vec_i.push_back(2);
41 vec_i.push_back(3);
42 for (int i=0 ; i < vec_i.size() ; ++i)
43 cout << vec_i[i] << endl;
44
45 char *area = (char*)mymalloc(20);
46 char *a1 = new char [20];
47
48 int j_ret = 9;
49 //printf("aaa\n");
50 //getchar();
51 j_ret = my_setjmp(jbuf);
52
53 if (j_ret == 0)
54 {
55 printf("00\n");
56 }
57 else
58 {
59 printf("11\n");
60 return 0;
61 }
62
63 my_longjmp(jbuf, 5);
64 return 0;
65 }
build -p AppPkg/AppPkg.dsc 就可以編譯出 m.efi 了, 不過先別急著打這個指令, 還要
寫個 script gcc (書上提供了一個, 照抄後再加上 g++ option, ref list 1), 判斷是
.c 檔時出動 gcc, .cpp 檔時出動 g++。當然也可能要修改
uefi/edk2/BaseTools/Scripts/GccBase.lds, 不過目前就不要搞太複雜, 這樣就可以了

list 1. gcc script
1 #!/bin/sh
3 iscpp=0
4 for i in "$@" ; do
5 if [ "-" != "${i:0:1}" ] ; then
6 if [ "cpp" = "${i##*.}" ]; then
7 iscpp=1
8 fi
9 fi
10 done
11
12 if [ $iscpp = 0 ]; then
13 echo gcc
14 /usr/bin/gcc -DUEFI $@
15 else
16 echo g++
18 /usr/bin/g++ -DUEFI -fpermissive -I. -DSTM32 -fno-exceptions -fno-rtti
-ffreestanding -nostdlib -nodefaultlibs -std=c++11 $@
19 fi
好了, 現在可以痛快的敲下 build -p AppPkg/AppPkg.dsc
fig 2 為測試畫面, ctor/dtor 正常發動了, lambda 也正常, DS::vector, DS::cout 也
正常, 感謝 bjarne stroustrup; 感謝 c++。
( https://goo.gl/NRsdfJ )
fig 2模擬器測試畫面
為了保險起見, 我在真實機器上同樣也做了測試, 真的是可以跑的。
( https://goo.gl/01E06B )
真實機器的 uefi 執行畫面
global object ctor/dtor 沒有搞定, 比我想的還複雜些, 這不是什麼問題, 不要用就好
了。 XD
我是用手動呼叫 GLOBAL_XX function 來搞定這件事。
uefi-shceme 就是這麼做的。
uefi function 手冊:
http://www.bluestop.org/edk2/docs/trunk/getchar_8c.html (
http://goo.gl/MsOT9J )
// 本文使用 Blog2BBS 自動將Blog文章轉成縮址的BBS純文字 http://goo.gl/TZ4E17 //
blog 版本:
http://descent-incoming.blogspot.tw/2016/03/c-uefiedk2-0.html
作者: ferocious   2016-06-25 23:32:00
cool
作者: justassassin (DK01)   2016-06-26 15:28:00
我有在AMI待一陣子,據我所了解C的記憶體效能還真比較快一點,另外很大原因是因為歷史包袱.
作者: Ethical (游志傑)   2016-06-27 11:31:00
有趣,推
作者: whitglint   2016-06-28 07:57:00
對 C++ 這麼有愛一定要推!
作者: besmartAE (*無敵海灘男孩*)   2016-06-29 13:04:00
推 加入UEFI大軍以後, 只寫C 就忘記如何寫C++了 XDDD
作者: saxontai (黑暗,點綴孤零零的星)   2016-06-30 23:37:00
有愛是一回事,不支援你愛的語言就說人家原始實在很奇怪
作者: ahwater01 (臭酸咖)   2016-07-01 11:40:00
我待的vendor,有C++寫的module阿,比較少而已
作者: Ommm5566 (56天團)   2016-07-01 17:12:00
→ saxontai: 有愛是一回事,不支援你愛的語言就說人家

Links booklink

Contact Us: admin [ a t ] ucptt.com