简体   繁体   English

编译Fortran外部符号

[英]Compiling Fortran external symbols

When compiling fortran code into object files: how does the compiler determine the symbol names? 将fortran代码编译为目标文件时:编译器如何确定符号名称?

when I use the intrinsic function "getarg" the compiler converts it into a symbol called "_getarg@12" 当我使用内部函数“getarg”时,编译器将其转换为名为“_getarg @ 12”的符号

I looked in the external libraries and found that the symbol name inside is called "_getarg@16" what is the significance of the "@[number]" at the end of "getarg" ? 我查看了外部库,发现里面的符号名称叫做“_getarg @ 16”,“getarg”末尾的“@ [number]”有什么意义?

_name@length is highly Windows-specific name mangling applied to the name of routines that obey the stdcall (or __stdcall by the name of the keyword used in C) calling convention, a variant of the Pascal calling convention. _name@length是高度特定于Windows的名称修改,应用于遵循stdcall (或通过C中使用的关键字名称的__stdcall )调用约定的惯例的名称,这是Pascal调用约定的变体。 This is the calling convention used by all Win32 API functions and if you look at the export tables of DLLs like KERNEL32.DLL and USER32.DLL you'd see that all symbols are named like this. 这是所有Win32 API函数使用的调用约定,如果查看像KERNEL32.DLLUSER32.DLL这样的DLL的导出表,您会看到所有符号都是这样命名的。

The _...@length decoration gives the number of bytes occupied by the routine arguments. _...@length修饰给出了例程参数占用的字节数。 This is necessary since in the stdcall calling conventions it is the callee who cleans up the arguments from the stack and not the caller as is the case with the C calling convention. 这是必要的,因为在stdcall调用约定中,被调用者清除堆栈中的参数而不是调用者,就像C调用约定一样。 When the compiler generates a call to func with two 4-byte arguments, it puts a reference to _func@8 in the object code. 当编译器使用两个4字节参数生成对func的调用时,它会在对象代码中引用_func@8 If the real func happens to have different number or size of arguments, its decorated name would be something different, eg _func@12 and hence a link error would occur. 如果真正的func恰好具有不同数量或大小的参数,则其装饰名称将是不同的,例如_func@12 ,因此会发生链接错误。 This is very useful with dynamic libraries (DLLs). 这对动态库(DLL)非常有用。 Imagine that a DLL was replaced with another version where func takes one additional argument. 想象一下,DLL被另一个版本替换,其中func需要一个额外的参数。 If it wasn't for the name mangling (the technical term for prepending _ and adding @length to the symbol name), the program would still call into func with the wrong arguments and then func would increment the stack pointer with more bytes than was the size of the passed argument list, thus breaking the caller. 如果它不是名称mangling(用于预先添加_并将@length添加到符号名称的技术术语),程序仍将使用错误的参数调用func ,然后func将增加堆栈指针的字节数超过传递的参数列表的大小,从而打破了调用者。 With name mangling in place the loader would not launch the executable at all since it would not be able to resolve the reference to _func@8 . 随着名称的修改,加载器根本无法启动可执行文件,因为它无法解析对_func@8的引用。

In your case it looks like the external library is not really intended to be used with this compiler or you are missing some pragma or compiler option. 在您的情况下,看起来外部库实际上并不打算与此编译器一起使用,或者您缺少一些pragma或编译器选项。 The getarg intrinsic takes two arguments - one integer and one assumed-sized character array (string). getarg内在函数有两个参数 - 一个整数和一个假设大小的字符数组(字符串)。 Some compilers pass the character array size as an additional argument. 一些编译器将字符数组大小作为附加参数传递。 With 32-bit code this would result in 2 pointers and 1 integer being passed, totalling in 12 bytes of arguments, hence the _getarg@12 . 使用32位代码,这将导致传递2个指针和1个整数,总共12个字节的参数,因此_getarg@12 The _getarg@16 could be, for example, 64-bit routine with strings being passed by some kind of descriptor. 例如, _getarg@16可以是64位例程,其中字符串由某种描述符传递。

As IanH reminded me in his comment, another reason for this naming discrepancy could be that you are calling getarg with fewer arguments than expected. 正如IanH在评论中提醒我的那样,这种命名差异的另一个原因可能是你使用比预期更少的参数调用getarg Fortran has this peculiar feature of "prototypeless" routine calls - Fortran compilers can generate calls to routines without actually knowing their signature, unlike in C/C++ where an explicit signature has to be supplied in the form of a function prototype. Fortran具有“无原型”例程调用的这一特殊功能 - Fortran编译器可以在不知道其签名的情况下生成对例程的调用,这与C / C ++不同,后者必须以函数原型的形式提供显式签名。 This is possible since in Fortran all arguments are passed by reference and pointers are always the same size, no matter the actual type they point to. 这是可能的,因为在Fortran中所有参数都通过引用传递,并且指针始终具有相同的大小,无论它们指向的实际类型如何。 In this particular case the stdcall name mangling plays the role of a very crude argument checking mechanism. 在这种特殊情况下, stdcall名称修改起着非常粗略的参数检查机制的作用。 If it wasn't for the mangling (eg on Linux with GNU Fortran where such decorations are not employed or if the default calling convention was cdecl ) one could call a routine with different number of arguments than expected and the linker would happily link the object code into an executable that would then most likely crash at run time. 如果它不是用于修改(例如在使用GNU Fortran的Linux上没有使用这样的装饰或者默认调用约定是cdecl ),可以调用具有与预期不同数量的参数的例程,并且链接器将愉快地链接该对象代码转换为可执行文件,然后很可能在运行时崩溃。

This is totally implementation dependent. 这完全取决于实现。 You did not say, which compiler do you use. 您没有说,您使用的是哪个编译器。 The (nonstandard) intrinsic can exist in more versions for different integer or character kinds. 对于不同的整数或字符种类,(非标准)内在函数可以存在于更多版本中。 There can also be more versions of the runtime libraries for more computer architectures (eg 32 bit and 64 bit). 对于更多计算机体系结构(例如32位和64位),还可以有更多版本的运行时库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM