NASM调用外部C ++函数 [英] NASM call for external C++ function

查看:511
本文介绍了NASM调用外部C ++函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从NASM调用外部C ++函数.当我在Google上搜索时,我没有找到任何相关的解决方案.
C ++

I am trying to call external C++ function from NASM. As I was searching on google I did not find any related solution.
C++

void kernel_main()
{
    char* vidmem = (char*)0xb8000;
    /* And so on... */
}

NASM

;Some calls before
section     .text
    ;nothing special here

global start
extern kernel_main ;our problem

运行这两个文件的编译后,出现此错误:kernel.asm(.text+0xe): undefined reference to kernel_main' 这是怎么了谢谢.

After running compiling these two files I am getting this error: kernel.asm(.text+0xe): undefined reference to kernel_main' What is wrong here? Thanks.

推荐答案

到目前为止,尚无从汇编中调用C ++函数的标准化方法.这是由于称为 name-mangling 的功能所致. C ++编译器工具链不会发出符号,这些符号的名称必须完全写在代码中.因此,您不知道代表用kernel_mainkernelMain编码的函数的符号的名称是什么.

There is no standardized method of calling C++ functions from assembly, as of now. This is due to a feature called name-mangling. The C++ compiler toolchain does not emit symbols with the names exactly written in the code. Therefore, you don't know what the name will be for the symbol representing the function coded with the name kernel_main or kernelMain, whatever.

为什么需要名称更改?

您可以在C ++中用相同的名称声明多个实体(类,函数,方法,名称空间等),但在不同的父名称空间下.如果具有名称本地名称的两个实体(例如,名称空间SymbolDomain中的class SomeContainer的本地名称为SomeContainer但全局名称为SymbolDomain::SomeContainer,至少要在此答案中讨论,好的)会导致符号冲突名称.

You can declare multiple entities (classes, functions, methods, namespaces, etc.) with the same name in C++, but under different parent namespaces. This causes symbol conflicts if two entities with the name local name (e.g. local name of class SomeContainer in namespace SymbolDomain is SomeContainer but global name is SymbolDomain::SomeContainer, atleast to talk in this answer, okay) have the same symbol name.

方法重载也会发生冲突,因此,类的方法也会发出(以某种形式)每个参数的类型.为了解决这个问题,C ++工具链将以某种方式修改ELF二进制对象中的实际名称.

Conflicts also occur with method overloading, therefore, the types of each argument are also emitted (in some form) for methods of classes. To cope with this, the C++ toolchain will somehow mangle the actual names in the ELF binary object.

所以,我不能在汇编中使用C ++乱码吗?

是的,这是一种解决方案.您可以将readelf -s fileNamekernel_main的目标文件一起使用.您必须搜索与kernel_main相似的符号.一旦您认为得到了它,然后用echo _ZnSymbolName | c++filt确认,它应该输出kernel_main.

Yes, this is one solution. You can use readelf -s fileName with the object-file for kernel_main. You'll have to search for a symbol having some similarity with kernel_main. Once you think you got it, then confirm that with echo _ZnSymbolName | c++filt which should output kernel_main.

您在程序集中使用此名称而不是kernel_main.

You use this name in assembly instead of kernel_main.

此解决方案的问题是,如果由于某种原因而更改了参数,返回值或其他任何内容(我们不知道是什么影响名称处理),则汇编代码可能会中断.因此,您必须对此小心.另一方面,这不是一个好习惯,因为您要研究非标准的东西.

The problem with this solution is that, if for some reason, you change the arguments, return value, or anything else (we don't know what affects name-mangling), your assembly code may break. Therefore, you have to be careful about this. On the other hand, this is not a good practice, as your going into non-standard stuff.

请注意,名称处理不是标准化的,并且随工具链的不同而不同.通过依赖它,您也可以使用同一编译器.

Note that name-mangling is not standardized, and varies from toolchain to toolchain. By depending on it, your sticking to the same compiler too.

我不能做标准化的事情吗?

是的.您可以通过这样声明函数extern "C"来在C ++中使用C函数

Yep. You could use a C function in C++ by declaring the function extern "C" like this

extern "C" void kernelMain(void);

这是您的最佳解决方案,因为您的kernel_main已经是C样式的函数,没有父类和名称空间.请注意,C函数是用C ++编写的,并且仍然(内部)使用C ++功能.

This is the best solution in your case, as your kernel_main is already a C-style function with no parent class and namespace. Note that, the C function is written in C++ and still uses C++ features (internally).

其他解决方案包括使用宏间接寻址,如果您确实需要的话,C函数可以调用C ++函数.像这样-

Other solutions include using a macro indirection, where a C function calls the C++ function, if you really need to. Something like this -

///
/// Simple class containing a method to illustrate the concept of
/// indirection.
///
class SomeContainer
{
public:
     int execute(int y)
     {

     }
}

#define _SepArg_ , // Comma macro, to pass into args, comma not used directly

///
/// Indirection for methods having return values and arguments (other than
/// this). For methods returning void or having no arguments, make something
/// similar).
///
#define _Generate_Indirection_RetEArgs(ret, name, ThisType, thisArg, eargs) \
extern "C" ret name ( ThisType thisArg, eargs ) \
{                                     \
    return thisArg -> name ( eargs );         \
}                                     \

_Generate_Indirection_RetEArgs(int, execute, SomeContainer, x, int y);

这篇关于NASM调用外部C ++函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆