python main 函数()函数是C程序的入口点怎么理解

代码逆向(一)――寻找main函数入口_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
代码逆向(一)――寻找main函数入口
上传于||文档简介
&&寻​找​m​a​i​n​函​数​入​口
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩4页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢DSP编程技巧之21---在main函数运行之前,你需要知道的
> DSP编程技巧之21---在main函数运行之前,你需要知道的
DSP编程技巧之21---在main函数运行之前,你需要知道的
  在一个程序能正常运行之前,相关的运行时(run-time)环境首先要正确建立。在CCS软件编程的情况下,的实时运行库RTS的源程序库rts.src中包含了名为boot.c或者boot.asm的启动程序(在一些TI的例子里,则使用了CodeStartBranch.asm来完成启动工作,它会自动调用库文件中的boot.asm),用于在系统启动后调用c_int00函数,并通过其中的操作来完成运行时环境的建立。通常情况下,c_int00函数位于rts2800.lib库函数中的boot.obj(即TI官方编译boot.c或者boot.asm生成的目标文件)下,这也就是为什么我们在C28x编程的情况下通常要把rts2800.lib库函数加入工程中的原因(其它器件则根据型号、系列添加对应的库文件;否则就会出现初学者经常遇到的找不到boot.c之类的错误)。本文引用地址:
  注:小型内存模型含义是已初始化的段被链接至低 64Kw(字)可寻址空间内的非易失性内存,它使用rts2800.lib。对于定点器件,如果使用大内存模型(超过64K字),则需要使用库 rts2800_ml.对于含有FPU的器件,用于标准 C 语言代码的为 rts2800_fpu32.lib,或者用于 C++ 代码的 rts2800_fpu32_eh.lib(没有针对浮点器件的较小内存模型库)。在 CCS v5/v6 中,有一个针对库的&自动&设置,此设置可据项目的设置(例如,浮点支持和内存模型选择)让 CCS 自动选择正确的库来使用。对于 /BIOS 项目,/BIOS 将负责将所需的库包括在内,我们用户不需要在项目中包含任何运行支持库。
  如果在链接器选项中我们使用了--ram_model或者--rom_mode(具体含义请参考.cn/article/249328.htm),则_c_int00函数自动被配置为整个程序执行的入口点。此外,在CPU复位之后(相当于一个软件或者硬件的复位中断),我们也可以把整个程序的入口点指向_c_int00,例如:
  .def _Reset
  .ref _c_int00
  _Reset: .vec _c_int00, USE_RETA
  则在执行CPU复位操作之后,系统自动跳转到_c_int00函数。
  在c_int00函数中完成的功能主要有:
  1. 设置/初始化CPU的状态和配置寄存器。
  2. 为系统的栈定义一个.stack段(关于各个段的含义,请参考.cn/article/256732.htm),然后建立并初始化栈的指针。其中,栈需要被分配在单一的、连续的一段地址中,起始点为低地址,终点为高地址,栈指针SP的初始化值指向栈的顶端。
  3. 从初始化表中,把数据复制到.bss段中,从而初始化全局变量。如果使用了&ram_model选项在加载程序时就初始化变量,则在程序运行前,会首先运行一个加载程序来完成变量的初始化。如果使用了--rom_model选项,则使用.cinit中的运行时初始化表来完成变量的初始化。
  默认情况下,链接器使用--rom_model选项,在程序运行时完成变量的自动初始化。在程序运行时,.cinit段和其它初始化的段会被一起加载到内存中,从而使得C/C++的启动程序可以自动把.cinit中的初始化表格复制到.bss段中,完成全局变量的自动初始化。这种方法的特点在于,初始化的表格可以被存放在更加便宜且大容量的ROM或者FLASH,而不是RAM中,并且可以在程序启动时再自动加载到RAM中,这种方法在我们把程序烧写到FLASH中再运行的时候是经常使用的。关于Flash运行的更多信息,可以参考TI的的一个应用报告:.cn/cn/lit/an/zhca550l/zhca550l.pdf,从 TMS320F28xxx 数字信号处理器 () 上的内部闪存存储器上运行一个应用。
  如果使用&ram_model的链接器选项,则链接器会在.cinit段的开头中配置STYP_COPY位(0010h),告诉加载器不要把.cinit段自动加载到内存中,并且把cinit这个符号设置为-1(默认情况下符号cinit指向初始化表格),从而向启动程序表明,内存中没有初始化表格,在启动时不需要执行运行时的初始化工作。在这种情况下,需要我们自定义一个加载程序,从而在加载程序时就完成初始化,它的主要内容包括:
  & 在目标文件中检测.cinit段的存在;
  & 在.cinit段的开头配置STYP_COPY位,使得该段不会被自动复制到内存中;
  & 需要我们理解并正确遵循初始化表格的格式。
  这三个注意点貌似比较复杂,不过有读者可能会问,我们在直接把程序通过JTAG下载到DSP的RAM中并运行的时候,貌似并没有配置这么麻烦的步骤啊?那是因为CCS编程环境已经帮我们承担了这一重要任务,在我们用仿真器来调试、运行的时候经常会使用到这个方式。
  注意:在C/C++程序运行之前,一些全局变量必须被赋予初始值。在ANSI/ISO C中,未明确初始化的全局和静态变量在程序执行前都需要被初始化为0,C/C++的编译器并不会对它们进行自动初始化。在把程序加载到RAM而不是ROM中的情况下,比较方便的方法是直接把.bss段初始化为0。
  而在C28x DSP的编程中,如果一个全局变量的初值并不会对程序的运行结果产生任何影响,则我们一般不用考虑给它们赋初值,因为编译器会使用.cinit段中的初始化表格来初始化变量,叫做自动初始化autoinitialization,其示意图为:
  在使用了--ram_model或者--rom_mode选项的情况下,链接器在把所有C/C++模块中的相关变量初始化的内容链接入.cinit段之后,会自动在其末尾加入null关键字,来标明初始化表格的末尾。
  4.调用.pinit中的所有的全局构造函数。
  .pinit段中的内容相对简单,它主要包含了构造的地址列表。在.cinit初始化完成之后,构造函数的地址就出现在构造函数地址列表中了。
  在使用了--ram_model或者--rom_mode选项的情况下,链接器在把所有C/C++模块中的构造函数的地址链接入.pinit段之后,会自动在其末尾加入null关键字,来标明构造函数地址的结束。
  与.cinit段不同的时,不管使用--ram_model还是--rom_mode选项,.pinit段都会在运行时被加载和处理。
  5.调用main()函数,执行我们的程序。
  6.在main()函数返回时,调用exit函数。
  根据需要,我们可以自定义启动函数,但是一定要保证我们的自定义函数能够正确完成以上的步骤以建立C/C++的实时运行库环境,否则我们的程序将无法正常运行,甚至根本无法运行。
c++相关文章:
分享给小伙伴们:
我来说两句……
最新技术贴
微信公众号二
微信公众号一& 本篇博客是对C语言函数部分的重点内容和细枝末节通过实战得到的经验的总结精炼,不涵盖C语言函数的全部内容,所有提炼内容均来自提炼与实战,阅读需要对函数部分有一定基础,可用于对C语言函数的理解提升和备考复习,理解本文有助于您解决C语言函数部分的题目,获得只有通过实战才能加深理解的经验。&
& 大家都大致都了解一点数学意义上&函数&的概念,比如&y=f (x)&,且不论f的具体形式如何,其基本特点是&对一个x,有一个y值与之对应&。C语言中,&函数&是个重要的概念,是模块化编程的基础。
& 什么是函数?&根据输入进行处理返回输出。&&
函数精要与细枝末节
1.函数概念
函数的别称是方法,函数也就是完成某一特定功能的模块,main函数是C程序的入口点,有且仅有一个main函数。
2.函数的执行流程函数调用必须等待函数执行完成才会执行下一步。
3.库函数与自定义函数
库函数:由C语言系统提供;用户无须定义,也不必在程序中作类型说明;只需在程序前包含有该函数定义的头文件;自定义函数:用户在程序中根据需要而编写的函数;
4.函数在VS编译器中的特点
函数名在VS里可以参杂中文
C语言参数过多会警告,多的会忽略,结果不保证正确,C语言保证尽量类型一致,个数一致。
C语言函数不return返回可以编译,但是结果自负。
C语言函数一定要加声明,加了声明一定不会出错,不加声明有可能出错,声明可以有多个,定义只能有一个,理论上一定要加声明。
VS2013的编译器,默认的配置了静态库lib的路径。
C语言编译比较宽泛,有库的路径,可以自动定位,不需要函数声明;C++必须有函数声明,头文件,库文件。
std标准库,C语言标准跨平台。
可以用abort()函数来处理程序的异常。
5.函数的返回值就是函数的输出,函数的结果
main函数可以没有返回值,无论类型是int还是void。
C非main函数如果不是void,会有一个警告,如果是CPP会是一个错误。
6.return后面得语句不会再被执行main函数的return语句就是退出,没有return,main函数执行完所有语句就会退出
7.函数的形参与实参
& 函数调用的时候,形参分配内存,新建一个变量,存储传递过来的实参。函数调用之前,形式参数,也就是函数定时时()里的参数,值都不确定,不确定的值,不会分配内存,只有调用函数的时候,才会分配内存新建一个变量,接受实际参数的值,当函数调用结束的时候,形参占据的内存会被回收。实际参数是函数调用的时候,函数传递的确切值就是实际参数,实际参数可以是常量,变量或者表达式。形参与实参内存地址不一样,占用不同的内存空间。
& 形式参数与实际参数的类型,会自动完成数据类型的转换,调用函数的时候,尽量类型要匹配,否则会出现误差或错误。
8.局部变量与全局变量
局部变量:局部变量调用完成以后会被回收,局部变量是为块语句服务的,函数内部定义的变量,还有函数的参数,都是局部变量
全局变量:全局变量不属于任何一个函数,可以被任何一个函数调用,全局变量的生存期就是程序的生命期,全局变量会一直占内存,而局部变量用完就扔。
全局变量可以用于函数的通信,同名的情况下,局部变量会屏蔽全局变量。
C++可以用::访问全局变量,C语言不可以。同一个块语句下变量不可以重名,可以再装一个块语句。
int //全局变量声明,没有初始化默认为0,有的话就是默认的值
int a=9; //全局变量定义,只能有一个
全局变量,跨文件都可以调用如果重名,局部变量会屏蔽全局变量,内部块语句变量会屏蔽外部变量全局变量,很容易被覆盖,很容易被读写
局部变量没有声明与定义的区别
int add(int ,int ); //声明的变量名可以省略,要加分号,声明要与定义匹配
9.输入输出函数
putchar(); //按字符打印
getchar(); //等待你输入一个字符,返回值就是你输入的字符
10.函数声明与定义
C语言从上往下开始编译,所以上面如果没有函数的定义,或者声明就无法找到函数,无法调用。
函数的实体只能有一个,函数的声明,只是说明函数的存在,所以可以有多个。
C++属于严格的编程语言,函数的声明必须在调用之前
11.函数是模块化编程的基础,函数解决代码重用的问题
函数可以把相对独立的某个功能抽象出来,使之成为程序中的一个独立实体。可以在同一个程序或其他程序中多次重复使用。
12.函数的块语句不允许省略
函数体内部变量不可以与参数同名
参数传递是单向值传递
(void) 参数为空
函数的默认类型是int,可以省略
13.函数的副本机制
函数除了数组外,都是副本,副本机制通过赋值,赋值会自动类型转换。return也会完成类型转换
14.字符串输入输出
%i等价于%d,打印有符号十进制数据
//输入一个字符串到字符串变量
getchar(); //等待你输入一个字符的作用
sleep()函数在windows.h头文件里
15.函数的执行顺序:
从下往上进栈,从上往下执行。
16.函数参数运算顺序:
从右面的参数开始算 (int a,int b) 先计算b的值,再计算a的值,从右往左
show(a,a++); //执行结果6,5
实战&&可变参数函数的实现
1.int类型可变参数函数实现:
#include&stdarg.h& // 标准参数
int add(int num,...) //...代表可变参数
int res=0; //结果
va_ //存储参数开始的地址
va_start(argp,num); // 从首地址开始,读取num后面的数据
for(int i=0;i&i++)
res+=va_arg(argp,int); //读取一个数据按照int类型解析
va_end(argp); //结束读取
2.字符串类型可变参数函数实现:
void go(int num,...)
va_ //存储参数开始的地址
va_start(argp,num); // 从首地址开始,读取num后面的数据
for(int i=0;i&i++)
char str[50];
sprintf(str,"%s",va_arg(argp,char *));
system(str); //读取一个数据按照char *解析
va_end(argp); //结束读取
3.如果是参数的个数也不知道情况:
void showint(int start,...)
va_ //存储参数开始的地址
va_start(argp,start); // 从首地址开始,读取num后面的数据
int argvalue= //第一步初始化
printf("\n%d",argvalue);
argvalue=va_arg(argp,int); //不断读取
}while(argvalue!=-1);
va_end(argp); //结束读取
阅读(...) 评论()C语言的主函数main中参数的含义是什么?
在C语言刚开始的学习中,我们知道main函数是程序的入口函数,每次程序执行都是从main函数开始,一般对于初学者,书上会用这样的框架让你书写程序:
int main()
上边的框架没有任何问题,对于初学者来说更是不错的选择。但是等你看其它的参考资料的时候,你会发现很多书上的main函数都会带有参数:main
(int argc,char *argv[])
这看上去确实很奇怪,不过等你学完函数的知识,你会发现main函数也没有什么。简单的来说就是带有两个参数,第一个参数是一个整形变量,第二个参数是一个指向字符串的指针数组。唯一可能会让人感觉疑惑的就是程序运行,谁来调用它们?答案很简单:操作系统来调用,并给它们赋值。
现在的操作系统都是图形化的,参数的调用基本都隐藏起来,不过可以借助DOS来理解:
在DOS操作系统中输入这样的命令:C:&可执行文件名
参数参数……;&
操作系统调用C语言的程序也是这样调用的。第一个参数argc代表命令中参数的个数,文件名也算上。argv就是存储这些参数的。为了验证结果的真实性,我写了一个示例程序将参数argv的结果输出:
&iostream&
using namespace
int main(int argc, char
for(int i=0; i& i++)
&&&&&&&&&&&&&&&&&&
cout&&argv[i]&&
将程序结果放入D盘,进入windows控制台,用命令运行该程序,结果如图:
我一共输入四个参数,算上程序名,刚好5个。也就是说在运行test.exe程序的时候,操作系统调用test的主函数main,并对其赋值。第一个参数argc的数值为五,第二参数agrv相当于二维数组,每一行存一个参数,共五行。大家可以试试!
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 requirejs main 入口 的文章

 

随机推荐