我如何知道将映射到哪些寄存器函数参数?
How do I know what registers function parameters will be mapped on?
我已经为 Brainfuck 编写了一个 JITting VM。它需要创建一个可写+可执行的内存区域(它是一个 char*
,但不是用 malloc
或 new
创建的),它充满了机器操作码(在我的例子中是 x64) ,然后在将 char*
转换为函数指针后调用。新创建的函数有参数。即,内存指针和其他一些内部的东西。
它可以工作,但它假定了特定的寄存器映射。那个映射已经改变了,曾经有一段时间,因为我将调用周围的代码更改为 char*
并且编译器决定它可以更好地与其他寄存器一起工作。所以我不得不改变代码生成方案。
恐怕我可以做一些会让编译器再次更改它的事情,或者更糟的是,使用堆栈,我还不知道如何从中提取参数。
所以我需要:
- 一种告诉编译器将参数放在哪些寄存器上的方法(`register ... asm("r0"),如 here 所述,不适用于参数)
- 还有一种了解参数映射到哪些寄存器的方法。那会使事情复杂化,但它仍然可行。
- 还有一种方法可以知道参数是否以及以何种顺序传递到堆栈
我正在使用 gcc 4.8.2。
当您调用一个函数时,编译器通常*无法选择将调用参数放在何处。这是由 ABI. If your host program is written in C++ and runs on a Linux/x86-64 machine, it will generally emit code that conforms to the calling convention described in the SysV ABI 规定的,其中包含以下参数传递规则:
If the class is INTEGER, the next available register of the sequence %rdi,
%rsi, %rdx, %rcx, %r8 and %r9 is used.
值得注意的是,INTEGER class 也包含指针参数。
这里的底线是你的 jitted 代码应该能够从上面列出的寄存器中选择它的参数。如果这仍然无法正常工作,我怀疑您可能对指令进行了错误的编码。尝试从 GDB 查看反汇编。
(*) 好吧,如果不能从翻译单元外部调用该函数,编译器可能会提供更多的灵活性。
我已经为 Brainfuck 编写了一个 JITting VM。它需要创建一个可写+可执行的内存区域(它是一个 char*
,但不是用 malloc
或 new
创建的),它充满了机器操作码(在我的例子中是 x64) ,然后在将 char*
转换为函数指针后调用。新创建的函数有参数。即,内存指针和其他一些内部的东西。
它可以工作,但它假定了特定的寄存器映射。那个映射已经改变了,曾经有一段时间,因为我将调用周围的代码更改为 char*
并且编译器决定它可以更好地与其他寄存器一起工作。所以我不得不改变代码生成方案。
恐怕我可以做一些会让编译器再次更改它的事情,或者更糟的是,使用堆栈,我还不知道如何从中提取参数。
所以我需要:
- 一种告诉编译器将参数放在哪些寄存器上的方法(`register ... asm("r0"),如 here 所述,不适用于参数)
- 还有一种了解参数映射到哪些寄存器的方法。那会使事情复杂化,但它仍然可行。
- 还有一种方法可以知道参数是否以及以何种顺序传递到堆栈
我正在使用 gcc 4.8.2。
当您调用一个函数时,编译器通常*无法选择将调用参数放在何处。这是由 ABI. If your host program is written in C++ and runs on a Linux/x86-64 machine, it will generally emit code that conforms to the calling convention described in the SysV ABI 规定的,其中包含以下参数传递规则:
If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used.
值得注意的是,INTEGER class 也包含指针参数。
这里的底线是你的 jitted 代码应该能够从上面列出的寄存器中选择它的参数。如果这仍然无法正常工作,我怀疑您可能对指令进行了错误的编码。尝试从 GDB 查看反汇编。
(*) 好吧,如果不能从翻译单元外部调用该函数,编译器可能会提供更多的灵活性。