Assembly - 除了 C 和 C++ 之外,是否还有其他语言允许使用内联代码与 Assembly 进行交互?
Assembly - Are there any languages other than C and C++ that allow for interaction with Assembly using inline code?
我最近阅读了这篇标题为 Embedded Systems/Mixed C and Assembly Programming
的文档
它基本上涉及 C 和 C++ 如何允许用户通过称为 内联汇编 的技术使用汇编代码,看起来有点像这样:
#include<stdio.h>
void main() {
int a = 3, b = 3, c;
asm {
mov ax,a
mov bx,b
add ax,bx
mov c,ax
}
printf("%d", c);
}
我想知道在其他 high-level 语言(如 Java、Python 和其他语言中是否可以进行类似的交互,或者这是否只能通过 C 和 C++ 实现。
是的,D、Rust、Delphi,以及其他一些提前编译语言有某种形式的内联汇编。
Java 没有,大多数其他通常从可移植二进制文件进行 JIT 编译的语言也没有(例如 Java 的 .class 字节码,或 C# 的 CIL) . Code injecting/assembly inlining in Java?.
像 Python 这样的非常高级的语言甚至没有简单的数字对象表示,例如一个整型变量 只是 一个 32 位对象,它有类型信息,并且(特别是在 Python 中)对于大值可以是任意长度。因此,即使 Python 实现确实具有内联汇编功能,让您对 Python 对象执行任何操作也是一个挑战,但可能 是 [=57] 的 NumPy 数组除外=] 像 C 数组一样布局。
可以从大多数高级语言调用本机机器代码函数(例如,从 C 编译的库,或手写的 asm)——这对于编写一些种应用。例如,在 Java 中有 JNI(Java 本机接口)。即使 node.js Java脚本也可以调用原生函数。将参数“编组”成一种有意义的形式传递给 C 函数可能会很昂贵,这取决于高级语言以及您是否想让 C / asm 函数修改数组或只是 return 一个值.
不同语言中内联汇编的不同形式
它们通常不是 MSVC 的低效形式,就像您使用的那样(forces a store/reload for inputs and outputs)。更好的设计,例如以 GNU C 内联 asm 为模型的 Rust,可以使用寄存器。例如像 GNU C asm("lzcnt %1, %0" : "=r"(leading_zero_count) : "rm"(input));
让编译器选择一个输出寄存器,并为输入选择寄存器或内存寻址模式。
(但更好的是 使用内在函数 ,如 _lzcnt_u32
或 __builtin_clz
用于编译器知道的操作,仅内联 asm 用于编译器不知道的指令'没有内在函数,或者如果您想以某种方式微优化循环。https://gcc.gnu.org/wiki/DontUseInlineAsm)
一些(如Delphi)通过类似于函数调用的“调用约定”输入,寄存器中有参数,不是完全自由混合 asm 和高级代码。所以它更像是一个具有固定输入的 asm 块,一个输出在特定寄存器中(加上副作用),编译器可以像函数一样内联。
对于像您显示的那样工作的语法,或者
- 您必须手动 save/restore 您在 内部 asm 块中使用的每个寄存器(除非您包装一个大循环,否则这对性能非常不利 - 显然是 Borland Turbo C++是这样的)
- 或者编译器必须理解每一条指令才能知道它可能写入哪些寄存器(MSVC就是这样)。 Rust 的内联 asm 的设计说明/讨论提到了 D or MSVC compilers to implement what's effectively a DSL (Domain Specific Language) 的这一要求,以及需要多少额外工作,特别是对于新 ISA 的可移植性。
请注意,MSVC 对内联 asm 的特定实现非常脆弱和笨重,以至于 doesn't work safely in functions with register args,这意味着它根本不支持 x86-64 或标准调用约定使用的 ARM/AArch64注册参数。相反,它们基本上为每条指令提供了内在函数,包括像 invlpg
这样的特权指令,使得在 Visual C++ 中编写内核(例如 Windows)成为可能。 (其他编译器希望您使用 asm()
来处理此类事情)。 Windows 几乎可以肯定有一些部分是在单独的 .asm 文件中编写的,比如中断和系统调用入口点,也许还有一个上下文切换函数,它必须加载一个新的堆栈指针,但是有良好的内在支持你不不需要 asm,如果你相信你的编译器可以自己制作足够好的 asm。
您可以在 HolyC 中进行内联汇编。
我最近阅读了这篇标题为 Embedded Systems/Mixed C and Assembly Programming
的文档它基本上涉及 C 和 C++ 如何允许用户通过称为 内联汇编 的技术使用汇编代码,看起来有点像这样:
#include<stdio.h>
void main() {
int a = 3, b = 3, c;
asm {
mov ax,a
mov bx,b
add ax,bx
mov c,ax
}
printf("%d", c);
}
我想知道在其他 high-level 语言(如 Java、Python 和其他语言中是否可以进行类似的交互,或者这是否只能通过 C 和 C++ 实现。
是的,D、Rust、Delphi,以及其他一些提前编译语言有某种形式的内联汇编。
Java 没有,大多数其他通常从可移植二进制文件进行 JIT 编译的语言也没有(例如 Java 的 .class 字节码,或 C# 的 CIL) . Code injecting/assembly inlining in Java?.
像 Python 这样的非常高级的语言甚至没有简单的数字对象表示,例如一个整型变量 只是 一个 32 位对象,它有类型信息,并且(特别是在 Python 中)对于大值可以是任意长度。因此,即使 Python 实现确实具有内联汇编功能,让您对 Python 对象执行任何操作也是一个挑战,但可能 是 [=57] 的 NumPy 数组除外=] 像 C 数组一样布局。
可以从大多数高级语言调用本机机器代码函数(例如,从 C 编译的库,或手写的 asm)——这对于编写一些种应用。例如,在 Java 中有 JNI(Java 本机接口)。即使 node.js Java脚本也可以调用原生函数。将参数“编组”成一种有意义的形式传递给 C 函数可能会很昂贵,这取决于高级语言以及您是否想让 C / asm 函数修改数组或只是 return 一个值.
不同语言中内联汇编的不同形式
它们通常不是 MSVC 的低效形式,就像您使用的那样(forces a store/reload for inputs and outputs)。更好的设计,例如以 GNU C 内联 asm 为模型的 Rust,可以使用寄存器。例如像 GNU C asm("lzcnt %1, %0" : "=r"(leading_zero_count) : "rm"(input));
让编译器选择一个输出寄存器,并为输入选择寄存器或内存寻址模式。
(但更好的是 使用内在函数 ,如 _lzcnt_u32
或 __builtin_clz
用于编译器知道的操作,仅内联 asm 用于编译器不知道的指令'没有内在函数,或者如果您想以某种方式微优化循环。https://gcc.gnu.org/wiki/DontUseInlineAsm)
一些(如Delphi)通过类似于函数调用的“调用约定”输入,寄存器中有参数,不是完全自由混合 asm 和高级代码。所以它更像是一个具有固定输入的 asm 块,一个输出在特定寄存器中(加上副作用),编译器可以像函数一样内联。
对于像您显示的那样工作的语法,或者
- 您必须手动 save/restore 您在 内部 asm 块中使用的每个寄存器(除非您包装一个大循环,否则这对性能非常不利 - 显然是 Borland Turbo C++是这样的)
- 或者编译器必须理解每一条指令才能知道它可能写入哪些寄存器(MSVC就是这样)。 Rust 的内联 asm 的设计说明/讨论提到了 D or MSVC compilers to implement what's effectively a DSL (Domain Specific Language) 的这一要求,以及需要多少额外工作,特别是对于新 ISA 的可移植性。
请注意,MSVC 对内联 asm 的特定实现非常脆弱和笨重,以至于 doesn't work safely in functions with register args,这意味着它根本不支持 x86-64 或标准调用约定使用的 ARM/AArch64注册参数。相反,它们基本上为每条指令提供了内在函数,包括像 invlpg
这样的特权指令,使得在 Visual C++ 中编写内核(例如 Windows)成为可能。 (其他编译器希望您使用 asm()
来处理此类事情)。 Windows 几乎可以肯定有一些部分是在单独的 .asm 文件中编写的,比如中断和系统调用入口点,也许还有一个上下文切换函数,它必须加载一个新的堆栈指针,但是有良好的内在支持你不不需要 asm,如果你相信你的编译器可以自己制作足够好的 asm。
您可以在 HolyC 中进行内联汇编。