Friday, June 4, 2010

vptr 跟 pointer to member function

good article on vptr
http://www.dreamincode.net/forums/topic/45816-detail-about-how-vptr-and-virtual-table-works/


and 一兩年前的信


Hi
我昨天在看WebKitcode  有看到一行怪怪的code

(m_object->*m_function)(this);  //請注意  ->*

我本身對c++不熟 但是問了一些熟c++的朋友 他們也不是很清楚
回去看了Stroustup的書 也不是講的很清楚 只有一頁 ( 媽的爛書.....)
不過大概知道這是pointer to member function
pointer to member function 是一個比較少人知道c++特有的feature

不過有整理出一些point出來

1.  pointer to member function is NOT pointer to function

void (Test::*pmfn)(void)      void (*pfn)(void)       是不一樣的  即使他們的return type, signature是一樣的
另外也不能把他castgeneric pointer (void *)
可以參考 c++ lite faqpage
http://www.parashift.com/c++-faq-lite/pointers-to-members.html


2. pointer to member function is NOT a pointer to some address

一個pointer to member function , 他只是一個class offset的位置而已
( EX: c++ 有個virtual function table的東西 而這pointer to member function只是這table中的offset)
而不是指到Memory中某段的address
另外 他的sizeof 不一定是4(on 32bit), 有些compiler會給他8 bytelength

3. dereference pointer to member function 要用 .*  or ->*
這也就是我看到那行怪怪code的東西
. -> 的時機就跟C一樣 object pointer時就用 ->


然後我寫個test 給大家看看

#include
using namespace std;
class test {
    public:
        void func();
        void func1();
        void (test::*pmfn)();  //注意這是個 pointer to member function
                                        // 而且要加test:: ,如果沒有 他就只是一般的pointer to function
                                        // 就是下面那行的  (*pfn)()
        void (*pfn)();
        void call_pmfn(test&); //這是要用 test::*pmfn call function的一個wrapper
};
void test::func()
{
    cout<<"test::func\n";
}
void test::func1()
{
    cout<<"test::func1\n";
}
void func()
{
    cout<<"func\n";
}
void test::call_pmfn(test& t)
{
//    (this->*pmfn)();  //這就是call pointer to member function的地方
    (t.*pmfn)();          //在這裡我用兩個範例  , both can work
}
int main()
{
    test t;

    /* pointer to function */
    t.pfn = &func;  //這裡就是我們一般熟悉的pointer to function
    (t.pfn)();

    /* general pointer to member function */
    void (test::*pmfn1)() = &test::func1; //這裡是一般書上跟網頁上教你如何使用pointer to member function的東西
    (t.*pmfn1)();                                    //  請看待會後面的註解1

    /* pointer to member function
     * declared inside class, it is also a member of this class */
    t.pmfn = &test::func;

    //後記20090224  最後發現 (t.*t.pmfn)()也可以
    //(t.*pmfn)(); /*error here!  'pmfn' was not declared in this scope*/  
    //我在上面這行一直遇到compile error 這也是我的朋友們無法回答我問題的地方
    // 請看後面的註解2
    t.call_pmfn(t);
  
    return 0;
}


註解1
注意這個pmfn1 不是 test裡的member , 即使他有 test::開頭
因為他並沒有declaretest 裡面
其他的 test::func , test::func1可以definetest 外面  是因為他們也有在test 裡面被declared

加了test::開頭 是要告訴compile 這個pointer to member是要指到哪個class裡的member
compile 在這行 同時也會把test refernce傳給這個 pmfn1
(Recall第二點, pointer to member function 並沒有指到memory中的address
所以這時compiler要把class 的資訊告訴 pmfn1)


註解2
如果這裡 pmfn pmfn1一樣用 (t.*pmfn)()的話
是會有compile error出來的
大概原因(大概指的是我沒有很確定  我是從gdb猜的 而不是看gccsource code)
在這 compile沒有像  pmfn1一樣 有把testinformation pmfn
因為compiler在這就把pmfn當作一般的class member一樣
所以當 (t.*pfmn)()  ,compiler找不到pfmn是哪個classpointer to member /*這裡就是我不確定的地方*/
so compile will issue a error here

解決的辦法是
member function 跟一般的function有個不一樣的地方
就是他多了一個hiddenparameter , this
所以我作了一個wrapper member function
藉由this (也可以傳 test&進來) refernce call pointer to member function
也就是code裡的 test::call_pmfn()

不過至於pointer to member function什麼時候用
就要參考一些design pattern的書了

與大家分享一下C++特別的地方

thanks

Thursday, May 20, 2010

使用TARGET_GLOBAL_LD_DIRS

在這個hack裡
http://go2.wordpress.com/?id=725X1342&site=xorl.wordpress.com&url=http%3A%2F%2Fwww.frasunek.com%2Fproto_ops.tgz&sref=http%3A%2F%2Fxorl.wordpress.com%2F2009%2F08%2F18%2Fcve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference%2F

用了TARGET_GLOBAL_LD_DIRS
來用自己的linker script

Monday, May 17, 2010

__thread inside struct

忽然想到
如果__thread可以放到struct裡不就很刺激

小試了一下

26 struct test_t {
 27     int a;
 28     __thread int b;
 29 };

當然是會有compile error ......

Thursday, May 6, 2010

android build system

在combo/linux-arm.mk
default 是 build for  armv5te

另外在這makefile裡還有很多compiler flags

會找到這是因為要試試LOCAL_NO_DEFAULT_COMPILER_FLAGS=true
不然compile都會先找framework裡的header (無奈)

Friday, April 30, 2010

為什麼mmap size跟root有關系?

http://groups.google.com/group/android-kernel/browse_thread/thread/497ba1a48c3cd710

原因在這
http://lwn.net/Articles/342330/
http://xorl.wordpress.com/2009/08/18/cve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference/
http://www.securityfocus.com/archive/1/archive/1/505751/100/0/threaded

第二個link http://xorl.wordpress.com/2009/08/18/cve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference/

有講到三個hack

http://go2.wordpress.com/?id=725X1342&site=xorl.wordpress.com&url=http%3A%2F%2Fwww.grsecurity.net%2F~spender%2Fwunderbar_emporium.tgz&sref=http%3A%2F%2Fxorl.wordpress.com%2F2009%2F08%2F18%2Fcve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference%2F
這用了
oxff
0x25

0xff 0x25其實就是jmp的opcode
找個例子 objdump -D 就看出來了

http://go2.wordpress.com/?id=725X1342&site=xorl.wordpress.com&url=http%3A%2F%2Fwww.frasunek.com%2Fproto_ops.tgz&sref=http%3A%2F%2Fxorl.wordpress.com%2F2009%2F08%2F18%2Fcve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference%2F

這用了0x90 0xe9

跟最後一個比較簡單的
http://go2.wordpress.com/?id=725X1342&site=xorl.wordpress.com&url=http%3A%2F%2Fmilw0rm.com%2Fsploits%2Fandroid-root-20090816.tar.gz&sref=http%3A%2F%2Fxorl.wordpress.com%2F2009%2F08%2F18%2Fcve-2009-2692-linux-kernel-proto_ops-null-pointer-dereference%2F

opengl from donut to eclair

從donut到eclair,  loading OPENGLES 的方式有點不一樣
there is some difference of loading opengles lib from donut to eclair

check EGL first if you dont know what it is
http://www.khronos.org/egl/

on donut,
software impl for OPENGLES is /system/lib/libagl,
hardware is /system/lib/libhgl

on eclair
software impl is moved to /system/lib/egl/libGLES_android.so
hardware impl is moved to /system/lib/egl/lib{EGL,GLESv1_CM,GLESv2}_"vendor"
for example, on Acer A1 , it's system/lib/egl/libEGL_adreno200.so
                                                                      libGLESv1_CM_adreno200.so
                                                                      libGLESv2_adreno200.so


check framework/base/opengl/libs/EGL/egl.cpp on both branches to see the difference

Wednesday, April 28, 2010

using JNI in pthread

有人問到為什麼不能在native pthread create出來的 thread "直接" 使用 JNI

在這explain 一下 background

大家知道Thread之間是會shared memory的 (不過stack當然還是自己的)
所以大家寫code 有時會用個global 變數  然後兩三個thread來對這global變數作read/write

不過大概在2000年吧?   ABI (Binary Interface)那時有作一些update 
http://www.sco.com/developers/gabi/2000-07-17/contents.html
主要就是多個TLS - Thread Local Storage
就是讓thread 有自己的global 變數 其他的thread並不會踩到別thread的memory

例如  原本的 int g_is_vm_started;
GCC的話 :  在前面加個 __thread  就變成 thread variable了
__thread int g_is_vm_started;
在這看你自己喜歡的compile怎麼改
http://en.wikipedia.org/wiki/Thread-local_storage

而JNI 也是有用到這東西
所以在call JNI時  VM會去拿TLS裡的pointer  裡面存著vm在這個thread裡的context
如果想看Dalvik的code的話
就是在vm/Jni.c裡的 JNI_ENTER() 這macro裡
( 不過Android上其實並沒有Runtime support TLS
用readelf dump library裡其實並沒有.tdata .tbss的section
上面講的TLS 其實是bionic 裡的pthread 自己作出來的
)


想在pthread create出來的thread裡使用JNI
可以先看這
http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/invocation.html

還有個在pthread裡的ClassLoader的問題
http://groups.google.com/group/android-ndk/browse_thread/thread/7982fdb5892f79fb