微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

GNU 汇编器的 .struct 指令 - 如何实例化类实例?

如何解决GNU 汇编器的 .struct 指令 - 如何实例化类实例?

出于教育目的,我正在尝试使用 GNU 程序集创建一个面向对象的类。我对 .struct 指令的使用有很多疑问:

  1. 据说这个指令将代码切换到绝对节。为什么它被命名为 .struct 呢?和C的struct有关系吗?

  2. 使用有什么区别:

.set    Object.data,8
.set    Object.func_pointer,16

和使用

    .struct 0
Object: 
Object.data:
    .struct Object + 8
Object.func_pointer:
    .struct Object.data + 8
Object_size = . - Object

这实际上是使用 .struct 指令的方式还是误用?老实说,我什至不知道我在用 .struct 指令做什么。我觉得没用?

  1. 我在下面提供的完整代码将手动分配 Object 类的一个实例。如果我想在任何时候使用构造函数来实例化类,我是否需要将我的对象移到堆栈上以及如何完成?使用 .bss 我可以命名我的实例(例如 test_object),但我不确定我是否可以命名堆栈地址。

完整代码,以便您可以理解我在说什么:(GNU as,Linux x64)

    .data
msg:    .asciz  "Hello World!\n"
.set    msglen,. - msg


# CLASS struct
# This class struct only hold pointers to functions available for the class
    .struct 0
Object: 
# Class variables
Object.data:
    .struct Object + 8
# Class pointers
Object.func_pointer:
    .struct Object.data + 8
Object_size = . - Object

# Allocate Object_size bytes in the bss section to store the object instance
    .bss
test_object:
    .space  Object_size



#----------------------------------------------------------------------------
# Code starts here
    .text
#----------------------------------------------------------------------------

# Simple hello world function used as the target
hellofunc:
    push    %rbp
    mov %rsp,%rbp
    mov $1,%rax
    mov $1,%rdi
    mov $msg,%rsi
    mov $msglen,%rdx
    syscall
    leave
    ret

# Initiate the Object class by:
#   Allocate a chunk of Object_size bytes on the stack
#   Load value given in %rdi into Object.data
#   Load the address of hellofunc into Object.func_pointer
initiate:
    # Prologue
    push    %rbp
    mov %rsp,%rbp
    # Make %rdx point at the current object instance
    mov $test_object,%rdx
    # Load hellofunc address onto test_object.func_pointer
    mov $hellofunc,%rax
    mov %rax,Object.func_pointer(%rdx)
    # Load data from %rdi onto test_object.data
    mov %rdi,Object.data(%rdx)
    # Test call to see if test_object.func_pointer is properly loaded
    call    *Object.func_pointer(%rdx)
    # Epilogue
    leave
    ret

#---------------------------------------------------------------------------
# Main function
    .globl  _start
#---------------------------------------------------------------------------
_start:
    mov $0xDEADBEEF,%rdi
    call    initiate

    # return(0);
    mov $60,%rax
    mov $0,%rdi
    syscall

解决方法

我很确定你从任何汇编语言中得到的所有 struct 语法都是偏移量的符号名称,以及一种使用与你相同的 .space 指令来定义它们的方法'通常用于为 BSS 中结构的一个静态实例保留空间。例如,这就是 NASM 为您提供的内容,而 GAS 的内容甚至比这更简陋。

所以是的,它就像 C 中的 struct foo {int x; char c;}; 定义:您使用的语法看起来像声明(为)全局变量声明(为)全局变量,但您只是定义了结构的布局。 (除了在 GAS 中,您只能使用 .space 和类似的不能取值的指令,例如,不能将一个 int 与 4 个字符的数组区分开来。)

但在 GAS 中,它是如此原始,是的,这只是一种方式 分别设置一堆名称为 Object.func_pointer 的汇编时常量。您也可以使用 Object.func_pointer = 8 做完全相同的事情。


使用:(.set) 和 (.struct) 的区别是什么

没什么。这就是它为你所做的一切。没有任何类似于 struct 对象的概念,它只是您可以用来获取偏移的符号名称的工具的一部分。他们选择将其称为 .struct,因为这是一个用例。

但是,您通过重复使用 .struct 来不必要地重复自己(the example in the GAS manual does this,too;我不知道为什么)。 AFAIK 您必须在每个标签中重复结构名称(因为 GAS .struct 语法不是很复杂),但您可以使用 .space 而不必命名前一个字段。

    .struct 0
Object: 
#    .space 4
Object.obdata:
    .space 8
Object.func_pointer:
    .space 8
Object_size = . - Object

.text
mov $Object.obdata,%eax
mov $Object.func_pointer,%ecx

gcc -c foo.s && objdump -drwC -Mintel foo.o

...
   0:   b8 00 00 00 00          mov    eax,0x0
   5:   b9 08 00 00 00          mov    ecx,0x8

切换到绝对部分后您选择定义的名称 100% 由您决定,并且与结构的任何整体名称无关。


NASM 的结构支持更复杂一点:您可以在一个位置定义布局,并在静态初始化它的实例时使用这些成员名称(例如在 .data 部分)。 Nasm - access struct elements by value and by address 有一个例子。请注意,它涉及 endstruciend 指令,因为您实际上是在定义一个具有成员的结构,而不仅仅是单独设置一堆名称为 Object.func_pointer

的汇编时常量

诸如“构造函数”之类的其他任何事情都必须自己做。例如将成员写入内存中您决定的某个地方现在是结构对象的一个​​实例。

这是汇编语言,没有编译器,您需要在最终机器代码中显式编写任何指令。 (除非您使用 MASM,它在少数情况下会神奇地向您的代码添加指令。GAS 肯定不会;它主要设计为编译编译器生成的 asm。决定在某个点为“构造函数”发出指令是编译器在内部执行的操作,而不是通过任何特殊的 asm 语法。手写 asm 也是如此。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。