Assembly 汇编-英特尔语法中标签和函数之间的差异

Assembly 汇编-英特尔语法中标签和函数之间的差异,assembly,x86,Assembly,X86,我目前正在学习汇编,遇到了一些子程序。 既然它们是以相同的方式声明的,那么如何知道它们是标签还是子例程呢 label: subroutine: 我所知道的唯一一件事是,对子程序使用call,对标签使用jmp。我可能弄错了,但我相信在这种情况下,它们实际上是相同的 如果子例程是一个函数,那么也可以对它使用jmp 区别在于call允许子例程在需要时使用ret将控制权返回给调用者jmp不这样做,只修改程序计数器,而不留下任何关于它来自何处的信息 例如,这两种代码在行为上是等效的: foo: c

我目前正在学习汇编,遇到了一些子程序。 既然它们是以相同的方式声明的,那么如何知道它们是标签还是子例程呢

label:
subroutine:

我所知道的唯一一件事是,对子程序使用call,对标签使用jmp。

我可能弄错了,但我相信在这种情况下,它们实际上是相同的

如果子例程是一个函数,那么也可以对它使用
jmp

区别在于
call
允许子例程在需要时使用
ret
将控制权返回给调用者
jmp
不这样做,只修改程序计数器,而不留下任何关于它来自何处的信息

例如,这两种代码在行为上是等效的:

 foo:
  call B
  call A
  ret
将返回地址(调用指令后的地址)推送到堆栈上
ret
将堆栈弹出到RIP/EIP/IP中,返回给调用者(除非你把堆栈搞砸了)。因此,您可以在其他代码完成后返回到它,但是
jmp
只会转到其他代码


您调用的标签可能会选择不返回,例如,它可能会退出程序,就像C
exit()
函数一样,忽略返回地址。

子例程是一个概念性的东西,由一系列指令体现,即被调用、接受参数、执行某些操作,并可能向调用者返回一个值。子例程遵循某种调用约定,即关于如何传递参数和返回值以及如何在调用者和被调用者之间共享CPU寄存器的约定

标签仅命名代码或数据中的单个点。标签用于命名子例程的入口点、命名某些数据的开头、命名代码中用于构造控制流结构的点,如if-then-else,while do

在一些汇编器中,例如MASM,有一种特殊的语法可以用来识别子例程,不同于普通的标签;然而,这并不是通用的,而且许多汇编程序不会将子程序标签与其他标签区分开来

导出供其他文件使用的标签(例如,通过全局指令)通常是子例程(子例程入口点),但也可以是数据


下面是一个例子,说明了为什么我们有时认为标签标识代码中的一个点,而不是代码块或指令序列

...
if ( a0 == 0 ) { a1++; }
...
我们可能会在程序集的if goto标签样式中看到这一点(在MIPS程序集中):

上面的标签标识了该if then语句中then部分之后的点。通过在那里分支,我们跳过then部分,并将控制流转移到下一个语句,不管它是什么(这里用
表示)


由于if goto标签样式,组装使我们不断创建标签。命名标签可能很乏味,因此有时使用简单的标签更容易,例如L1、L2、L3。有些汇编程序支持使用编号标签,例如$1、$2(这些标签无法导出,有些汇编程序甚至可以在同一文件中重用这些数字,而不会产生冲突。)

如果是您的代码,那么您就知道了,因为您是做出此决定的人。如果是其他人的代码,您必须阅读文档、注释或代码本身,以找出是什么。有些人可能会在函数中使用本地或匿名标签,但这是可选的,而不是可以依赖的。子例程是有标签的。数据已标记。控件结构使用标签。有些标签是文件专用的,有些则导出供其他文件使用。在汇编语言中,没有一个更高级的子例程。是的,一些汇编语言具有将标签声明为过程或子例程的语法,以便更容易地导出、链接或读取代码。在一天结束时,标签是地址的抽象,子例程是一个高级概念,需要一个地址,通常使用标签进行编码,以便于编写代码。在汇编语言中,相同的标签可以用作函数调用指令的地址(取决于指令集,该指令是什么)作为分支目的地,汇编提供了这种自由。因此,即使您看到对标签的调用,而该调用并没有使该代码成为子例程,它也可能只是一些代码……英特尔语法并不定义汇编语言,只有汇编器定义汇编语言,而标签的语法是汇编器倾向于不同的一个领域。您使用的是什么特定的汇编程序和版本?谢谢您的详细回答,我现在就知道了:D@Ajvar:请注意,函数中的本地标签通常使用特殊语法,因此它们不会出现在对象文件的符号表中。Erik提到了一些特殊的名字,比如GAS语法中的
1f
(向前)或
1b
(向后),或者GAS语法中的
.Lname
。NASM本地标签以
开头,类似于
.loop:
(通过连接标签名称,其范围在某种程度上被限定为以前的非点标签)。顺便说一句,术语:标签定义了一个符号。谢谢你的回复,我觉得很奇怪,仅仅看代码就没有特定的语法来区分函数,问题解决了谢谢:D
...
if ( a0 == 0 ) { a1++; }
...
    ...
    bnez $a0, skipThen
    addi $a1, $a1, 1
skipThen:
    ...