注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

gcc局部变量装饰  

2012-02-26 00:27:15|  分类: Gcc源代码分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、局部函数
局部函数是gcc的一种扩展,也就是可以在函数中定义函数,乍一听不可思议,但是我们最早接触的PASCAL语言就是支持局部函数定义的,后来渐渐的就忘记了,当然是在接触了C语言之后。后来在看一个编译问题的时候就遇到一个问题,那就是一个函数定义在链接的时候死活找不到,但是从函数定义的地方看是木有问题的。当然如你所猜测的,这个函数定义被包含到了前面一个函数中,成了一局部函数。大家可能觉得好笑,怎么会犯这么低级的错误呢。事实上,这个函数前面有长长的注释,而且那个罩着这个函数定义的函数离这里又比较远,总之,各种误会吧,无巧不成书。
二、测试函数
[tsecer@Harry localfun]$ cat localfun.c
int main()
{
int foo(void) {return printf("In local fun\n");}
return foo();
}
[tsecer@Harry localfun]$ cat localfun.c ^C
[tsecer@Harry localfun]$  ../../gccObj/stage1-gcc/cc1  localfun.c
 main foo
localfun.c: In function ‘foo’:
localfun.c:3: warning: incompatible implicit declaration of built-in function ‘printf’

Execution times (seconds)
 parser                :   0.00 ( 0%) usr   0.00 ( 0%) sys   0.01 (12%) wall      29 kB ( 3%) ggc
 tree CFG construction :   0.00 ( 0%) usr   0.01 (25%) sys   0.01 (12%) wall       1 kB ( 0%) ggc
 expand                :   0.00 ( 0%) usr   0.00 ( 0%) sys   0.01 (12%) wall      11 kB ( 1%) ggc
 TOTAL                 :   0.00             0.04             0.08                859 kB
Extra diagnostic checks enabled; compiler may run slowly.
Configure with --disable-checking to disable checks.
[tsecer@Harry localfun]$ cat localfun.s
    .file    "localfun.c"
    .text
.globl main
    .type    main, @function
main:
    leal    4(%esp), %ecx
    andl    $-16, %esp
    pushl    -4(%ecx)
    pushl    %ebp
    movl    %esp, %ebp
    pushl    %ecx
    subl    $4, %esp
    call    foo.1526
    addl    $4, %esp
    popl    %ecx
    popl    %ebp
    leal    -4(%ecx), %esp
    ret
    .size    main, .-main
    .section    .rodata
.LC0:
    .string    "In local fun\n"
    .text
    .type    foo.1526, @function
foo.1526:没有设置为.globl所以为局部变量,这个局部变量后加了一个数字,用来保证同一个编译单元内唯一
    pushl    %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    $.LC0, (%esp)
    call    printf
    leave
    ret
    .size    foo.1526, .-foo.1526
    .ident    "GCC: (GNU) 4.2.0"
    .section    .note.GNU-stack,"",@progbits
[tsecer@Harry localtmode=V~
三、gcc中该变量生成路径
(gdb) bt
#0  get_identifier (text=0xbfffc260 "foo.1526")
    at ../../gcc-4.2.0/gcc/stringpool.c:110
#1  0x087c2858 in lhd_set_decl_assembler_name (decl=0xb7d7b620)
    at ../../gcc-4.2.0/gcc/langhooks.c:184
#2  0x088fc763 in decl_assembler_name (decl=0xb7d7b620)
    at ../../gcc-4.2.0/gcc/tree.c:305
#3  0x0893e8b1 in make_decl_rtl (decl=0xb7d7b620)
    at ../../gcc-4.2.0/gcc/varasm.c:1058
#4  0x084347a8 in rtx_for_function_call (fndecl=0xb7d7b620, addr=0xb7d7d120)
    at ../../gcc-4.2.0/gcc/calls.c:1458
#5  0x08436753 in expand_call (exp=0xb7d7c078, target=0xb7d7a7b0, ignore=0)
    at ../../gcc-4.2.0/gcc/calls.c:2560
#6  0x085abe4f in expand_expr_real_1 (exp=0xb7d7c078, target=0xb7d7a7b0,
    tmode=SImode, modifier=EXPAND_NORMAL, alt_rtl=0xbfffd918)
    at ../../gcc-4.2.0/gcc/expr.c:7671
#7  0x085a569b in expand_expr_real (exp=0xb7d7c078, target=0xb7d7a7b0,
    tmode=SImode, modifier=EXPAND_NORMAL, alt_rtl=0xbfffd918)
    at ../../gcc-4.2.0/gcc/expr.c:6700
#8  0x08599f26 in store_expr (exp=0xb7d7c078, target=0xb7d7a7b0,
    call_param_p=0) at ../../gcc-4.2.0/gcc/expr.c:4370
#9  0x0859933c in expand_assignment (to=0xb7cfa1b8, from=0xb7d7c078)
    at ../../gcc-4.2.0/gcc/expr.c:4249
#10 0x085b8acd in expand_expr_real_1 (exp=0xb7cf51b0, target=0x0,
---Type <return> to continue, or q <return> to quit---
    tmode=VOIDmode, modifier=EXPAND_NORMAL, alt_rtl=0x0)
    at ../../gcc-4.2.0/gcc/expr.c:8604
#11 0x085a569b in expand_expr_real (exp=0xb7cf51b0, target=0xb7cf1210,
    tmode=VOIDmode, modifier=EXPAND_NORMAL, alt_rtl=0x0)
    at ../../gcc-4.2.0/gcc/expr.c:6700
#12 0x088c05bb in expand_expr (exp=0xb7cf51b0, target=0xb7cf1210,
    mode=VOIDmode, modifier=EXPAND_NORMAL) at ../../gcc-4.2.0/gcc/expr.h:493
#13 0x088c7aab in expand_expr_stmt (exp=0xb7cf51b0)
    at ../../gcc-4.2.0/gcc/stmt.c:1364
#14 0x089a2924 in expand_gimple_basic_block (bb=0xb7cf62d0)
    at ../../gcc-4.2.0/gcc/cfgexpand.c:1383
#15 0x089a3956 in tree_expand_cfg () at ../../gcc-4.2.0/gcc/cfgexpand.c:1649
#16 0x08986420 in execute_one_pass (pass=0x8e894c0)
    at ../../gcc-4.2.0/gcc/passes.c:881
#17 0x0898655c in execute_pass_list (pass=0x8e894c0)
    at ../../gcc-4.2.0/gcc/passes.c:932
#18 0x081b2958 in tree_rest_of_compilation (fndecl=0xb7d7b5b0)
    at ../../gcc-4.2.0/gcc/tree-optimize.c:463
#19 0x0807e1c2 in c_expand_body (fndecl=0xb7d7b5b0)
    at ../../gcc-4.2.0/gcc/c-decl.c:6836
#20 0x08a931ab in cgraph_expand_function (node=0xb7d7b700)
    at ../../gcc-4.2.0/gcc/cgraphunit.c:1244
#21 0x08a90a4a in cgraph_assemble_pending_functions ()
---Type <return> to continue, or q <return> to quit---
    at ../../gcc-4.2.0/gcc/cgraphunit.c:374
#22 0x08a90e3c in cgraph_finalize_function (decl=0xb7d7b5b0, nested=0 '\000')
    at ../../gcc-4.2.0/gcc/cgraphunit.c:503
#23 0x0807e0b5 in finish_function () at ../../gcc-4.2.0/gcc/c-decl.c:6805
#24 0x08116ca8 in c_parser_declaration_or_fndef (parser=0xb7cf5120,
    fndef_ok=1 '\001', empty_ok=1 '\001', nested=0 '\000',
    start_attr_ok=1 '\001') at ../../gcc-4.2.0/gcc/c-parser.c:1435
#25 0x081166a1 in c_parser_external_declaration (parser=0xb7cf5120)
    at ../../gcc-4.2.0/gcc/c-parser.c:1192
#26 0x081163f4 in c_parser_translation_unit (parser=0xb7cf5120)
    at ../../gcc-4.2.0/gcc/c-parser.c:1095
#27 0x0812403b in c_parse_file () at ../../gcc-4.2.0/gcc/c-parser.c:7864
#28 0x080f4061 in c_common_parse_file (set_yydebug=0)
    at ../../gcc-4.2.0/gcc/c-opts.c:1182
#29 0x088f1a8e in compile_file () at ../../gcc-4.2.0/gcc/toplev.c:1033
#30 0x088f3262 in do_compile () at ../../gcc-4.2.0/gcc/toplev.c:2006
#31 0x088f32c4 in toplev_main (argc=2, argv=0xbffff394)
    at ../../gcc-4.2.0/gcc/toplev.c:2038
#32 0x0814cd22 in main (argc=2, argv=0xbffff394)
    at ../../gcc-4.2.0/gcc/main.c:35
相关函数
gcc-4.2.0\gcc\langhooks.c
/* Set the DECL_ASSEMBLER_NAME for DECL.  */
void
lhd_set_decl_assembler_name (tree decl)
{
  /* The language-independent code should never use the
     DECL_ASSEMBLER_NAME for lots of DECLs.  Only FUNCTION_DECLs and
     VAR_DECLs for variables with static storage duration need a real
     DECL_ASSEMBLER_NAME.  */
  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
          || (TREE_CODE (decl) == VAR_DECL
          && (TREE_STATIC (decl)
              || DECL_EXTERNAL (decl)
              || TREE_PUBLIC (decl))));
 
  /* By default, assume the name to use in assembly code is the same
     as that used in the source language.  (That's correct for C, and
     GCC used to set DECL_ASSEMBLER_NAME to the same value as
     DECL_NAME in build_decl, so this choice provides backwards
     compatibility with existing front-ends.
     
     Can't use just the variable's own name for a variable whose scope
     is less than the whole compilation.  Concatenate a distinguishing
     number - we use the DECL_UID.  */所以后面跟的数值是一个声明ID,从而保证整个编译单元内唯一。这是一个比较有意思的声明范围,例如static函数是声明为文件内唯一的,而这种局部函数则是函数内或者说一个声明域中唯一的,所以他有更小的范围。例如不同的函数内可以有相同的函数声明。这一点对于局部static变量同样适用,那么为什么要给它们命名呢?编译生成的是.o文件,最终连接的时候需要这些重定位信息
  if (TREE_PUBLIC (decl) || DECL_CONTEXT (decl) == NULL_TREE)
    SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl));
  else
    {
      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
      char *label;
     
      ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
      SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label));
    }
}
四、如何在gcc中找到调用链
其实方法是很笨的,就像很多所谓的黑客,破解了别人的密码,窃取了重要的信息,公布之后大家觉得相当了得,但事实上它可能是用穷举来破解的,途径是相当无趣的。或者像一些企业家,在其光鲜亮丽的背后,可能也经过了当初笨拙的尝试、彷徨的苦闷以及无边的寂寞。但是不管如何,我们总不能忘记当初的理想,要憧憬着美好。
对于这个查找,最重要的特征就是函数名后面有一个".number"的格式,可以大致猜测他是通过一个“.%d”或者".%u"之类的格式化字符串,所以就使用工具在整个gcc文件夹下搜索这个字符串".%"字符串,然后就会找到一些大致的范围,然后通过这些字符串相对应的名称可以找到大致哪些比较相似。然后使用调试器在调用这些函数的地方打上条件断点,条件就是我们源代码中特殊的变量名(例如上例中的“foo”,而比较条件就是!strncmp(var,"foo",3)),从而可以找到对应的调用链。
  评论这张
 
阅读(1149)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017