2023年12月2日发(作者:)

实时编译、动态执行CC++源码函数实时编译、动态执行C/C++源码函数 语法格式:fileCLASS *pObj = <>该语法获得源代码的函数接口对象指针pObj,通过pObj调用的函数。参数: : c/c++源代码文件名。返回值:fileCLASS *pObj: 接口对象地址。1. 编写c/c++源码函数接口struct rootCLASS //函数对象名字{ virtual char* _stdcall getstr(char *aptr); //定义函数0 virtual void _stdcall getval(double aval,char *aptr); //定义函数1 virtual double _stdcall sqrt(int aval); //定义函数2};头文件: root.h (定义了3个接口函数)#include "root.h" //定义对象的头文件char* rootCLASS::getstr(char *aptr) //实现函数0{ printf("江南好n%s",aptr); return `日出江花红似火, `;}void rootCLASS::getval(double aval,char *aptr) //实现函数1{ double dd = aval + 0.00002227; printf(`春来江水绿如蓝 -- "%0.8f"n%sn`,dd,aptr);}double rootCLASS::sqrt(int aval) //实现函数2{ return ::sqrt(aval);}rootCLASS ROOT; //声明接口变量void* main(void **pObj){ *pObj = &ROOT; //把接口地址传给用户 return []() //返回Lambda函数用于资源清理 { printf("Exit.n"); };}c/c++文件: (实现源码函数接口)2.编写程序调用的函数#include "root.h" //定义ROOT对象的头文件void main(){ rootCLASS *ROOT = <>; //该语句取出的函数对象地址 if(!ROOT) return; //若有语法错误,则ROOT=null printf("%sn",ROOT->getstr("风景旧曾谙n")); //调用的getstr函数 ROOT->getval(2014.0720,"能不忆江南"); //调用的getval函数 printf("%fn",ROOT->sqrt(3)); //调用的sqrt函数}c/c++文件: (调用函数)编译执行:用YC命令: ycc 生成 。执行后,输出下列文字:江南好风景旧曾谙日出江花红似火,春来江水绿如蓝 – “2014.07202227”能不忆江南1.732051Exit.分析:1. 文件和root.h一起为应用程序提供一个函数接口:rootCLASS ROOT。2. 语句rootCLASS *ROOT = <>将源代码编译转换为执行代码文件:www …之后执行代码被调入内存,变量rootCLASS

ROOT的地址被传给的主函数:void main(void **pObj){},主函数通过语句 *pObj = &ROOT 把的函数接口对象地址&ROOT传给的rootCLASS *ROOT。通过语句下列语句:ROOT->getstr()ROOT->getval()ROOT->sqrt()调用的接口函数。3. 程序退出时,自动检查主函数main()是否有函数指针返回,若有,则执行它,以便释放可能申请的系统资源。本例主函数的返回值为lambda函数:{ printf(“Exit.n”); };4. 将调入YC编辑器后,按Ctrl+F5键,生成下列汇编代码,分析汇编代码可更好地理解接口源码。#include "" 2020-01-11 12:40:30 0#include "include/ycapi.h" 2020-01-10 14:39:02 1#include "root.h" 2020-01-10 17:38:26 2 0 printf 1 sqrtvoid entry(){00000000 6800000000 push 0x0005 e802000000 call void *main(void **pObj) (0000000C=000000A+0000002)// 210000000A 59 pop ecx0000000B c3 ret} 20 arglen=4void *main(void **pObj){0000000C 8b442404 mov eax,dword [esp+04h]00000010 c700d8000000 mov dword [eax],0x000000D8 //struct rootCLASS ROOT ( 19)00000016 b884000000 mov eax,0x00000084 //global=00000017 返回函数的地址0000001B c3 ret} root.h 3 arglen=8 3virtual char *stdcall rootCLASS::getstr(char *aptr){0000001C 55 push ebp0000001C 55 push ebp0000001D 8bec mov ebp,esp0000001F 51 push ecx00000020 ff750c push dword [ebp+0Ch] //aptr ( 2)00000023 6890000000 push 0x00000090 //"江南好n%s" ( 4)00000028 e87fdbff8e call int printf(const char *_Format, ...) //include/stdio.h 2640000002D 83c408 add esp,0x0030 b89c000000 mov eax,0x0000009C //"日出江花红似火, " ( 5)00000035 8be5 mov esp,ebp00000037 5d pop ebp00000038 c20800 ret 0008} root.h 4 arglen=10 9virtual void stdcall rootCLASS::getval(double aval,char *aptr){0000003B 55 push ebp0000003C 8bec mov ebp,esp0000003E 83ec0c sub esp,0x0000000C00000041 dd450c fld qword [ebp+0Ch] //aval ( 8)00000044 dc05e8000000 fadd qword [000000E8] //zeroName (include/yca.h 0)0000004A dd5df8 fstp qword [ebp-08h] //dd ( 10)0000004D ff7514 push dword [ebp+14h] //aptr ( 8)00000050 ff75fc push dword [ebp-04h] //dd+4 (00064c99 + 4) ( 10)00000053 ff75f8 push dword [ebp-08h] //dd ( 10)00000056 68b0000000 push 0x000000B0 //"春来江水绿如蓝 -- "%0.8f"n%sn"0000005B e87fdbff8e call int printf(const char *_Format, ...) (8EFFDB7F)//stdio.h 26400000060 83c410 add esp,0x0063 8be5 mov esp,ebp00000065 5d pop ebp00000066 c21000 ret 0010} root.h 5 arglen=8 15virtual double stdcall rootCLASS::sqrt(int aval){00000069 55 push ebp0000006A 8bec mov ebp,esp0000006C 51 push ecx0000006D db450c fild dword [ebp+0Ch] //aval ( 14)00000070 83ec08 sub esp,0x0073 dd1c24 fstp qword [esp]00000076 e820dbff8e call double sqrt(double _X) (8EFFDB20) //include/math.h 5210000007B 83c408 add esp,0x007E 8be5 mov esp,ebp00000080 5d pop ebp00000081 c20800 ret 0008} 23 arglen=0void stdcall lamb_0000032() //Lambda函数虽在局部定义,却在全局实现{00000084 68d0000000 push 0x000000D0 //"Exit.n" ( 25)00000089 e87fdbff8e call int printf(const char *_Format, ...) //include/stdio.h 2640000008E 59 pop ecx0000008F c3 ret}// strings 代码中所用到的字符串

00000090 db 12 "江南好n%s" // 40000009C db 20 "日出江花红似火, " // 5000000B0 db 32 "春来江水绿如蓝 -- "%0.8f"n%sn" // 11000000D0 db 8 "Exit.n" // 25// variables 用户声明或编译器自动生成的全局变量 ///000000D8 struct rootCLASS ROOT dd 000000DC000000DC virtual char *stdcall rootCLASS::getstr(char *aptr) dd 0000001C000000E0 virtual void stdcall rootCLASS::getval(double aval,char *aptr) dd 0000003B000000E4 virtual double stdcall rootCLASS::sqrt(int aval) dd 00E8 zeroName dq 3EF75A0EBF358A7B000000F0 The End - 240 bytes// stack = 1 * 1048576 bytes5. 看看下面的汇编代码(在YC编辑器的工具菜单中生成),有助于理解该语法的实现过程。#include "" 2020-01-11 09:30:08 0#include "include/ycapi.h" 2020-01-10 14:39:02 1#include "root.h" 2020-01-10 17:38:26 2 0 YC_ExpFree 1 YC_ExpLoad 2 printf 2 arglen=0void main(){00000000 53 push ebx //ebx=ROOT ( 4)00000001 68a0000000 push 0x000000A0 //zeroName (include/yca.h 0)00000006 68a4000000 push 0x000000A4 //zeroName (include/yca.h 0)0000000B 68a8000000 push 0x000000A8 //zeroName (include/yca.h 0)00000010 e8f2d8ff8e call void stdcall YC_ExpLoad(void *pSrc,void *pHandle,void *pObj)00000015 8b1da0000000 mov ebx,dword [000000A0] //zeroName (include/yca.h 0)0000001B 85db test ebx,ebx0000001D 744e je 0000006D = 0000001F+0000004e0000001F 6884000000 push 0x00000084 //"风景旧曾谙n" ( 6)00000024 8bcb mov ecx,ebx00000026 51 push ecx00000027 8b01 mov eax,dword [ecx]00000029 ff10 call dword [eax] //调用ROOT->getstr()0000002B 50 push eax0000002C 6880000000 push 0x00000080 //"%sn" ( 6)00000031 e87fdbff8e call int printf(const char *_Format, ...) //include/stdio.h 26400000036 83c408 add esp,0x0039 6890000000 push 0x00000090 //"能不忆江南" ( 7)0000003E 6849789f40 push 0x409F784900000043 683f355eba push 0xBA5E353F00000048 8bcb mov ecx,ebx0000004A 51 push ecx0000004B 8b01 mov eax,dword [ecx]0000004D ff5004 call dword [eax+04h] //调用ROOT->getval()00000050 6a03 push 0x0052 8bcb mov ecx,ebx00000054 51 push ecx00000055 8b01 mov eax,dword [ecx]00000057 ff5008 call dword [eax+08h] //调用ROOT->sqrt()0000005A 83ec08 sub esp,0x005D dd1c24 fstp qword [esp]00000060 689c000000 push 0x0000009C //"%fn" ( 8)00000065 e87fdbff8e call int printf(const char *_Format, ...) //include/stdio.h 2640000006A 83c40c add esp,0x0000000C0000006D 5b pop ebx0000006E c3 ret}void yc_end() //由编译器根据是否有需要释放的资源而自动生成的函数,程序退出时自动执行{0000006F 68a4000000 push 0x000000A4 //zeroName (include/yca.h 0)00000074 68a8000000 push 0x000000A8 //zeroName (include/yca.h 0)00000079 e8f3d8ff8e call void stdcall YC_ExpFree(void *pSrc,void *pHandle) //yca.h 1330000007E c3 ret}// strings 代码中所用到的字符串

00000080 db 4 "%sn" // 600000084 db 12 "风景旧曾谙n" // 600000090 db 12 "能不忆江南" // 70000009C db 4 "%fn" // 8// variables用户声明或编译器自动生成的全局变量 //000000A0 zeroName dd 00000000 //ldpos=000000A0 include/yca.h 0000000A4 zeroName dd 00000000 //include/yca.h 0000000A8 zeroName dd 00000000 //include/yca.h 0000000AC The End - 172 bytes语法细节:1. 语句后面可跟0、1、2、3四个数字,其意义如下:ROOT = <> 0; pmt方式,是默认方式,0可省略。该方式中,的执行代码保存在www…文件,如果修改,则执行时将重新编译,若有语法错误,便弹出错误提示菜单,退出菜单后继续执行后面的代码。ROOT = <> 1; mem方式。该方式中,编译后的执行代码被保存在文件,的改动不会影响的执行。

ROOT = <> 2; nopmt方式。该方式中,的执行代码保存在www…文件,如果修改,则执行时将重新编译,若有语法错误,不提示而继续执行后面的代码。ROOT = <> 3; exit方式。该方式中,的执行代码保存在www…文件,如果修改,则执行时将重新编译,若有语法错误,便弹出错误提示菜单,退出菜单后便退出整个程序。2. 除方式1外,应该用语句 if(!ROOT){……} 判断是否有语法错误。如果.cpp文件不存在,则调用同名的.exp文件。如果.cpp或.exp文件在当前目录不存在,则在src目录寻找。3. 在yc.h中定义了下列4个宏:#define CPP_pmt 0#define CPP_mem 1#define CPP_nopmt 2#define CPP_exit 3可以使用这4个宏指定该语法的运行方式。4. 用VC++等其它编译器开发的程序不能使用该语法,但它们通过下面两个API函数可实现本语法的功能。void *YC_cppLoad(const char *srcbuf,int srclen, void *pObj,int isScript=0);void YC_cppFree(void *pHandle);5. YC开源代码中,下列文件使用了该语法。 YCJS = = <>; YCDRAW = = <>; YCHTML = = <>; = <>; = <>; = <>; = <>; YCCSS = = <>; YCOBJ = = <>; YCSTRING = ng = <>; YCARRAY = y = <>; YCDATE = = <>; YCDOM = = <>; e = <>; = <>; = <>;

ycx_ImageLoad = <> CPP_exit; YCREGEX = <>CPP_exit; YCTABLE = <>; YCFILTER = <>; YCFRAMESET = <>; ychttpCLASS *YCHTTP = <>; ycwinCLASS *pwin = <>;