From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1KBZgv-0003BX-BU for mharc-grub-devel@gnu.org; Wed, 25 Jun 2008 14:26:01 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KBZgr-0003A6-Vy for grub-devel@gnu.org; Wed, 25 Jun 2008 14:25:58 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KBZgr-00039n-C5 for grub-devel@gnu.org; Wed, 25 Jun 2008 14:25:57 -0400 Received: from [199.232.76.173] (port=58006 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KBZgr-00039j-5I for grub-devel@gnu.org; Wed, 25 Jun 2008 14:25:57 -0400 Received: from mailout08.t-online.de ([194.25.134.20]:42012) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1KBZgq-0006wA-4g for grub-devel@gnu.org; Wed, 25 Jun 2008 14:25:56 -0400 Received: from fwd33.aul.t-online.de by mailout08.sul.t-online.de with smtp id 1KBZgm-0006aJ-01; Wed, 25 Jun 2008 20:25:52 +0200 Received: from [10.3.2.2] (XN2OxwZpohCKXtjDzCfN04yFH23BBt7RA1F5wmYQanXMv1OOFTwjvCM1IO2DZUnghc@[217.235.226.87]) by fwd33.aul.t-online.de with esmtp id 1KBZgi-27qOrw0; Wed, 25 Jun 2008 20:25:48 +0200 Message-ID: <48628DAA.9060407@t-online.de> Date: Wed, 25 Jun 2008 20:25:46 +0200 From: Christian Franke User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7 MIME-Version: 1.0 To: The development of GRUB 2 References: <48583C04.219093.22092@m12-68.163.com> <1213762150.2940.15.camel@rd> <200806181956.37526.okuji@enbug.org> In-Reply-To: <200806181956.37526.okuji@enbug.org> Content-Type: multipart/mixed; boundary="------------020509020006030809070606" X-ID: XN2OxwZpohCKXtjDzCfN04yFH23BBt7RA1F5wmYQanXMv1OOFTwjvCM1IO2DZUnghc X-TOI-MSGID: 187f35dc-5063-4b32-8524-7c24326e14b1 X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 3) Subject: Re: Can grub2 support c++ module? (Patch) X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 25 Jun 2008 18:25:58 -0000 This is a multi-part message in MIME format. --------------020509020006030809070606 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Yoshinori K. Okuji wrote: > On Wednesday 18 June 2008 06:09:10 Pavel Roskin wrote: > >> On Wed, 2008-06-18 at 10:22 +0800, y.volta wrote: >> >>> Hi, >>> >>> I just wondering, can grub2 support module coded with c++? Let's >>> suppose we are trying to apply the fancy menu. ;-) >>> >> I think it can be done, but you'll need to disable exception handling >> and RTTI. You won't be able to use any C++ libraries. The build system >> will need to be changed to call C++ compiler when needed. >> >> Still, I think it would be an overkill. C is quite good for large >> projects if used properly. Linux is fine with C. C also has checkers >> such as sparse, but I'm not aware of C++ equivalents. >> > > When Vesa tried C++, the binary size got bloated, so it was abandoned. I am > afraid that C++ adds too much overhead. > > Hi, With exceptions/RTTI turned off and careful use of C++ features, C++ size overhead is close to zero. Even some overhead does not matter for modules which are typically not included into core.img. The problem using C++ in portable stand-alone programs like grub are the 'object machine' runtime support functions which differ between platforms and gcc releases. But if new/delete are replaced in the standard way and calls to other runtime support (like global/static ctors/dtors) are avoided, a reasonable C++ subset remains. The following C++ subset can be used: + classes, inheritance, virtual functions, virtual inheritance + objects allocated on stack, by new, and by placement new. + templates The following cannot be used: - global or static objects - try/catch/throw, dynamic_cast, RTTI - most of STL - nested functions (gcc supports these for C only) See attached patch for a working example. It adds some tests for basic C++ functionality to hello/hello.c. Some C++ support is provided by new includes mm.hpp and dl.hpp. No additions to kernel should be necessary (there might be some minor issues with kern/dl.c due to new symbol types). For testing purposes, hello.c can be compiled as a C++ source using: $ make hello_mod-hello_hello.o \ hello_mod_CFLAGS='-x c++ -fno-exceptions -fno-rtti $(COMMON_CFLAGS)' \ && make I also would appreciate support for grub modules written in C++. Christian --------------020509020006030809070606 Content-Type: text/x-diff; name="grub2-cpp-example.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="grub2-cpp-example.patch" diff -ruN grub2.orig/hello/hello.c grub2/hello/hello.c --- grub2.orig/hello/hello.c 2007-07-22 01:32:21.000000000 +0200 +++ grub2/hello/hello.c 2008-06-25 19:51:30.907250000 +0200 @@ -18,25 +18,164 @@ * along with GRUB. If not, see . */ + +// Include C++ support first +#include +#include + +extern "C" { // TODO: add extern "C" to all includes [__cplusplus] #include #include #include #include #include #include +} + + +// Class to set and restore grub_mm_debug in a block + +class do_mm_debug +{ +#ifdef MM_DEBUG +public: + explicit do_mm_debug (bool debug = true) + : m_debug_old (grub_mm_debug) + { grub_mm_debug = (int)debug; } + + ~do_mm_debug () + { grub_mm_debug = m_debug_old; } + +private: + int m_debug_old; +#else + +public: + do_mm_debug () { } + explicit do_mm_debug (bool) { } +#endif +}; + + + +// Classes to test single inheritance and vtable + +class A +{ +public: + explicit A (const char * name); + virtual ~A (); + + virtual void hello () const; + +protected: + char * m_name; +}; + +class B : public A +{ +public: + explicit B (const char * name); + virtual ~B (); + + virtual void hello () const; +}; + + + +A::A (const char * name) +: m_name (new char[grub_strlen (name) + 1]) // calls grub_fatal on failure +{ + grub_strcpy (m_name, name); + grub_printf ("%sA::A ()\n", m_name); +} + +A::~A () +{ + grub_printf ("%sA::~A ()\n", m_name); + delete [] m_name; +} + +void A::hello () const +{ + grub_printf ("%sA::hello (): Something wrong!\n", m_name); +} + + +B::B (const char * name) +: A (name) +{ + grub_printf ("%sB::B ()\n", m_name); +} + +B::~B () +{ + grub_printf ("%sB::~B ()\n", m_name); +} + +void B::hello () const +{ + grub_printf ("%sB::hello (): Hello C++ World\n", m_name); +} + + +// Globals + +//static B gb ("gb."); // NOT SUPPORTED + +static char gb_mem[sizeof (B)]; +B & gb = *(B *)gb_mem; // ctor called by placement new + +A * pa = 0; + + +static void +say_hello (const A & a) +{ + a.hello (); +} + static grub_err_t grub_cmd_hello (struct grub_arg_list *state __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { - grub_printf ("Hello World\n"); - return 0; + do_mm_debug here; + + // call virtual function B::hello () for all objects + + say_hello (gb); // global object + + if (pa) + { + say_hello (*pa); // global pointer (actually B *) + delete pa; + pa = 0; + } + + //static B sb ("sb."); // NOT SUPPORTED + //say_hello (&sb); + + B vb ("vb."); + say_hello (vb); // local object + + say_hello ( B("_temp_B.") ); // temporary object + + return GRUB_ERR_NONE; } GRUB_MOD_INIT(hello) { - (void)mod; /* To stop warning. */ + { + do_mm_debug here; + + pa = new (std::nothrow) B ("pa->"); + if (! pa) + return; + + new (gb_mem) B ("gb."); // returns &gb + } grub_register_command ("hello", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, "hello", "Say hello", 0); } @@ -44,4 +183,11 @@ GRUB_MOD_FINI(hello) { grub_unregister_command ("hello"); + + do_mm_debug here; + + gb.~B(); + + delete pa; + pa = 0; } diff -ruN grub2.orig/include/grub/dl.hpp grub2/include/grub/dl.hpp --- grub2.orig/include/grub/dl.hpp 1970-01-01 01:00:00.000000000 +0100 +++ grub2/include/grub/dl.hpp 2008-06-25 11:23:48.000000000 +0200 @@ -0,0 +1,37 @@ +// GRUB2 C++ GRUB_MOD_INIT/FINI + +#ifndef GRUB_DL_HPP +#define GRUB_DL_HPP 1 + +extern "C" { + #include // GRUB_MOD_INIT/FINI +} + + +// TODO: Add this to dl.h [__cplusplus] + +#undef GRUB_MOD_INIT +#undef GRUB_MOD_FINI + +#define GRUB_MOD_INIT(name) \ +extern "C" { \ + static void grub_mod_init (grub_dl_t mod __attribute__ ((unused))) __attribute__ ((used)); \ + void grub_##name##_init (void); \ +} \ +void \ +grub_##name##_init (void) { grub_mod_init (0); } \ +static void \ +grub_mod_init (grub_dl_t mod __attribute__ ((unused))) + +#define GRUB_MOD_FINI(name) \ +extern "C" { \ + static void grub_mod_fini (void) __attribute__ ((used)); \ + void grub_##name##_fini (void); \ +} \ +void \ +grub_##name##_fini (void) { grub_mod_fini (); } \ +static void \ +grub_mod_fini (void) + +#endif + diff -ruN grub2.orig/include/grub/mm.hpp grub2/include/grub/mm.hpp --- grub2.orig/include/grub/mm.hpp 1970-01-01 01:00:00.000000000 +0100 +++ grub2/include/grub/mm.hpp 2008-06-25 13:34:00.000000000 +0200 @@ -0,0 +1,102 @@ +// GRUB2 C++ memory management + +#ifndef GRUB_MM_HPP +#define GRUB_MM_HPP 1 + +extern "C" { + #include +} + + +// TODO: Add grub_malloc_nonull () to mm.c ??? + +static void * +grub_malloc_nonull (grub_size_t size) +{ + void * p = grub_malloc (size); + if (! p) + grub_fatal ("out of memory"); // no-exceptions, sorry + return p; +} + + +// TODO: add new/delete to [__cplusplus] + +// Standard (throw) new + +inline void * +operator new (grub_size_t size) +{ + return grub_malloc_nonull (size); +} + +inline void * +operator new[] (grub_size_t size) +{ + return grub_malloc_nonull (size); +} + + +// Standard nothrow new + +namespace std { + enum nothrow_t { nothrow }; +} + +inline void * +operator new (grub_size_t size, std::nothrow_t /*mode*/) throw () +{ + return grub_malloc (size); +} + +inline void * +operator new[] (grub_size_t size, std::nothrow_t /*mode*/) throw () +{ + return grub_malloc (size); +} + + +// Standard delete + +inline void +operator delete (void * ptr) throw () +{ + grub_free (ptr); +} + +inline void +operator delete[] (void * ptr) throw () +{ + grub_free (ptr); +} + + +// Placement new + +inline void * +operator new (grub_size_t /*size*/, void * here) throw () +{ + return here; +} + +inline void * +operator new[] (grub_size_t /*size*/, void * here) throw () +{ + return here; +} + + +// Placement delete (not used if no-exceptions) + +inline void +operator delete (void * /*ptr*/, void * /*here*/) throw () +{ +} + +inline void +operator delete[] (void * /*ptr*/, void * /*here*/) throw () +{ +} + +#endif + --------------020509020006030809070606--