我想知道在汇编中函数体什么时候结束,例如在c中,你有这个括号{},它告诉你函数体什么时候开始,什么时候结束,但是我怎么知道在汇编中呢?有没有一个解析器可以从程序集和函数体的起始行和结束行中提取出所有的函数?
gblwokeq1#
没有万无一失的方法,甚至可能没有一个定义明确的正确答案。通常(例如在编译器生成的代码中),当你看到下一个全局符号时,你就知道函数结束了,就像objdump决定什么时候打印一个新的“横幅”一样。但是如果所有的函数开始符号都不可见,就没有明确的方法。这就是为什么一些目标文件格式有空间来容纳与符号相关的大小元数据。就像GAS语法中的.size foo, . - foo。这并不像寻找一个ret那么容易;一些函数以jmp结尾调用另一个函数。一些call是一个无返回函数,如abort或__stack_chk_fail(而不是tailcall,因为它们要为回溯推送返回地址。)或者只是陷入下一个路径,因为该路径在源代码中有未定义的行为,所以编译器认为它不可访问,并停止为它生成指令,例如,C++非void函数,在没有return的情况下,执行可能/确实会从末尾脱落。一般来说,汇编会模糊函数的界限。Asm有一些特性可以用来 * 实现 * 函数的高级概念,但并不局限于此。例如,多个asm函数都可以通过跳转到一个公共代码块来返回,该代码块在ret之前弹出一些寄存器。共享tail是一个单独的函数吗?它是通过一个特殊的调用约定调用的tail调用的吗?编译器通常不会这样做,但人类可以。至于函数入口点,通常程序中的其他一些代码会包含一个call给它.但不一定;它可能只能通过函数指针表来访问,并且您不知道.rodata块是否包含函数指针,直到您发现一些代码从它加载并调用或跳转。
objdump
.size foo, . - foo
ret
jmp
call
abort
__stack_chk_fail
void
return
.rodata
**但如果函数的最低地址指令不是它的入口点,则该方法不起作用。**有关示例,请参见Does a function with instructions before the entry-point label cause problems for anything (linking)?
编译器不会生成这样的代码,但人类可以(对于https://codegolf.stackexchange.com/问题,这有时是一个很方便的技巧)。或者在一般情况下,一个函数可能有多个入口点。或者你可以把它描述为多个函数的重叠实现。有时候,它就像一个函数在不需要jmp的情况下通过尾部调用另一个函数一样简单,也就是说,它在另一个函数之前启动了几个指令。
mzillmmw2#
我不想知道函数体什么时候在汇编中结束,[...](用户空间)指令流的执行可以“结束”的方式主要有四种:1.无条件跳转,如jmp;有条件跳转,如Jcc(je,jnz,jg...)
Jcc
je
jnz
jg
ExitProcess
C
2条答案
按热度按时间gblwokeq1#
没有万无一失的方法,甚至可能没有一个定义明确的正确答案。
通常(例如在编译器生成的代码中),当你看到下一个全局符号时,你就知道函数结束了,就像
objdump
决定什么时候打印一个新的“横幅”一样。但是如果所有的函数开始符号都不可见,就没有明确的方法。这就是为什么一些目标文件格式有空间来容纳与符号相关的大小元数据。就像GAS语法中的.size foo, . - foo
。这并不像寻找一个
ret
那么容易;一些函数以jmp
结尾调用另一个函数。一些call
是一个无返回函数,如abort
或__stack_chk_fail
(而不是tailcall,因为它们要为回溯推送返回地址。)或者只是陷入下一个路径,因为该路径在源代码中有未定义的行为,所以编译器认为它不可访问,并停止为它生成指令,例如,C++非void
函数,在没有return
的情况下,执行可能/确实会从末尾脱落。一般来说,汇编会模糊函数的界限。
Asm有一些特性可以用来 * 实现 * 函数的高级概念,但并不局限于此。
例如,多个asm函数都可以通过跳转到一个公共代码块来返回,该代码块在
ret
之前弹出一些寄存器。共享tail是一个单独的函数吗?它是通过一个特殊的调用约定调用的tail调用的吗?编译器通常不会这样做,但人类可以。
至于函数入口点,通常程序中的其他一些代码会包含一个
call
给它.但不一定;它可能只能通过函数指针表来访问,并且您不知道.rodata
块是否包含函数指针,直到您发现一些代码从它加载并调用或跳转。**但如果函数的最低地址指令不是它的入口点,则该方法不起作用。**有关示例,请参见Does a function with instructions before the entry-point label cause problems for anything (linking)?
编译器不会生成这样的代码,但人类可以(对于https://codegolf.stackexchange.com/问题,这有时是一个很方便的技巧)。
或者在一般情况下,一个函数可能有多个入口点。或者你可以把它描述为多个函数的重叠实现。有时候,它就像一个函数在不需要
jmp
的情况下通过尾部调用另一个函数一样简单,也就是说,它在另一个函数之前启动了几个指令。mzillmmw2#
我不想知道函数体什么时候在汇编中结束,[...]
(用户空间)指令流的执行可以“结束”的方式主要有四种:
1.无条件跳转,如
jmp
;有条件跳转,如Jcc
(je
,jnz
,jg
...)ret
指令(表示子例程的结束),它可能最接近您的问题(包括ExitProcess
“ret”命令)的意图call
的另一个“函数”1.一个异常。不是
C
样式的异常,而是类似于“无效指令”或“除以0”的异常,它会终止用户空间程序[...]例如在c中,你有这个括号{},它告诉你函数体什么时候开始,什么时候结束,但是在汇编中我怎么知道呢?
简单的回答:**你不知道。**在机器级别上,每个地址(理论上)都可以是一个“函数”的入口点。因此,除了定义的入口点之外,没有唯一的“函数”入口点--你可以定义任何东西。
换句话说,这与自修改代码和病毒有关,但它一定不是。exit/end如上面第一部分所述。
有没有一个解析器可以从程序集和函数体的起始行和结束行中提取出所有的函数?
反汇编器创建了一些带有入口和出口点的“函数”。但是它们仅仅是 * 假定的 *。没有办法知道这个假设是否正确。这可能会导致问题。
通常的方法是使用反汇编程序,而将指令流重组为不同“函数”的工作仍由授权执行此任务的人员负责(vulgo:有些工具声称可以简化这一点,但我无法判断它们的有效性。
从高级语言的Angular 来看,存在试图将从(例如)C到汇编/机器码的转换反向的反编译器,其试图使该任务自动化,并且将或多或少地或在某些情况下工作。