link 个签名不匹配的函数
link functions with mismatching signature
我正在玩弄 gcc 和 g++ 编译器并尝试在其中编译一些 C 代码,我的目的是看看编译器/linker 如何强制执行当 link 将具有某些函数声明的模型转换为具有该函数实现的模型时,正确的函数是 linked(根据参数传递并返回值 )
例如让我们看一下这段代码
#include <stdio.h>
extern int foo(int b, int c);
int main()
{
int f = foo(5, 8);
printf("%d",f);
}
在我的符号 table 中编译后,我有一个 foo 的符号,但是在 elf 文件格式中没有描述所采用的参数和函数签名的地方,( int(int,int)
), 所以基本上如果我写一些像这样的其他代码:
char foo(int a, int b, int c)
{
return (char) ( a + b + c );
}
编译那个模型它也会有一些叫做 foo 的符号,如果我 link 这些模型在一起,会发生什么?我从来没有想过这一点,编译器将如何克服这个弱点……我知道在 g++ 中,编译器会为每个与其命名空间有关的符号生成一些前缀,但它是否也考虑了签名?如果有人遇到过这个问题,如果他能阐明这个问题就太好了
问题已解决with name mangling。
In compiler construction, name mangling (also called name decoration)
is a technique used to solve various problems caused by the need to
resolve unique names for programming entities in many modern
programming languages.
It provides a way of encoding additional information in the name of a
function, structure, class or another datatype in order to pass more
semantic information from the compilers to linkers.
The need arises where the language allows different entities to be
named with the same identifier as long as they occupy a different
namespace (where a namespace is typically defined by a module, class,
or explicit namespace directive) or have different signatures (such as
function overloading).
Consider the following two definitions of f() in a C++ program:
int f (void) { return 1; }
int f (int) { return 0; }
void g (void) { int i = f(), j = f(0); }
These are distinct functions, with no relation to each other apart
from the name. If they were natively translated into C with no
changes, the result would be an error — C does not permit two
functions with the same name. The C++ compiler therefore will encode
the type information in the symbol name, the result being something
resembling:
int __f_v (void) { return 1; }
int __f_i (int) { return 0; }
void __g_v (void) { int i = __f_v(), j = __f_i(0); }
Notice that g() is mangled even though there is no conflict; name
mangling applies to all symbols.
哇,我一直在自己探索和测试它,我想出了一个让我惊奇的解决方案,
所以我写了下面的代码并在gcc编译器上编译了它
main.c
#include <stdio.h>
extern int foo(int a, char b);
int main()
{
int g = foo(5, 6);
printf("%d", g);
return 0;
}
foo.c
typedef struct{
int a;
int b;
char c;
char d;
} mystruct;
mystruct foo(int a, int b)
{
mystruct myl;
my.a = a;
my.b = a + 1;
my.c = (char) b;
my.d = (char b + 1;
return my1;
}
现在我首先使用 gcc 将 foo.c
编译为 foo.o
并检查符号 table 使用
readelf
并且我有一些名为 foo
的条目
同样在我将 main.c
编译为 main.o
之后检查了符号 table 并且它还有一些名为 foo
的条目,我将这两个链接在一起并且令人惊讶它工作了,我 运行 main.o
并且显然遇到了一些分段错误,这是有道理的,因为 foo.o
中实现的 foo
的实际实现可能需要三个参数(第一个应该是struct adders), 一个在foo
定义下未传入main.o
的参数,然后实际实现从main
的堆栈帧访问一些不属于它的内存,然后尝试访问它认为它获得的地址,并以分段错误结束,没关系,
现在我用 g++ 而不是 gcc 再次编译了两个模型,结果令人惊讶。我发现符号foo.o
下的条目是 _Z3fooii
,main.o
下的条目是 _Z3fooic
,现在我的猜测是 ii
后缀表示 int int
和 ic
后缀表示 int char
这可能是指应该传递给函数的参数,因此允许编译器知道一些函数减速得到实际实现。所以我将 main.c
中的 foo
声明更改为
extern int foo(int a, int b);
重新编译,这次得到了符号 _Z3fooii
,我再次链接了两个模型,令人惊讶的是这次它成功了,我尝试了 运行,但再次遇到了分段错误,这也使得感觉编译器甚至不会总是授权正确的 return 值..无论如何我最初的想法是什么 - g++ 在符号名称中包含函数签名,从而强制链接器提供函数实现获取正确的参数以更正函数声明
我正在玩弄 gcc 和 g++ 编译器并尝试在其中编译一些 C 代码,我的目的是看看编译器/linker 如何强制执行当 link 将具有某些函数声明的模型转换为具有该函数实现的模型时,正确的函数是 linked(根据参数传递并返回值 )
例如让我们看一下这段代码
#include <stdio.h>
extern int foo(int b, int c);
int main()
{
int f = foo(5, 8);
printf("%d",f);
}
在我的符号 table 中编译后,我有一个 foo 的符号,但是在 elf 文件格式中没有描述所采用的参数和函数签名的地方,( int(int,int)
), 所以基本上如果我写一些像这样的其他代码:
char foo(int a, int b, int c)
{
return (char) ( a + b + c );
}
编译那个模型它也会有一些叫做 foo 的符号,如果我 link 这些模型在一起,会发生什么?我从来没有想过这一点,编译器将如何克服这个弱点……我知道在 g++ 中,编译器会为每个与其命名空间有关的符号生成一些前缀,但它是否也考虑了签名?如果有人遇到过这个问题,如果他能阐明这个问题就太好了
问题已解决with name mangling。
In compiler construction, name mangling (also called name decoration) is a technique used to solve various problems caused by the need to resolve unique names for programming entities in many modern programming languages.
It provides a way of encoding additional information in the name of a function, structure, class or another datatype in order to pass more semantic information from the compilers to linkers.
The need arises where the language allows different entities to be named with the same identifier as long as they occupy a different namespace (where a namespace is typically defined by a module, class, or explicit namespace directive) or have different signatures (such as function overloading).
Consider the following two definitions of f() in a C++ program:
int f (void) { return 1; } int f (int) { return 0; } void g (void) { int i = f(), j = f(0); }
These are distinct functions, with no relation to each other apart from the name. If they were natively translated into C with no changes, the result would be an error — C does not permit two functions with the same name. The C++ compiler therefore will encode the type information in the symbol name, the result being something resembling:
int __f_v (void) { return 1; } int __f_i (int) { return 0; } void __g_v (void) { int i = __f_v(), j = __f_i(0); }
Notice that g() is mangled even though there is no conflict; name mangling applies to all symbols.
哇,我一直在自己探索和测试它,我想出了一个让我惊奇的解决方案,
所以我写了下面的代码并在gcc编译器上编译了它
main.c
#include <stdio.h>
extern int foo(int a, char b);
int main()
{
int g = foo(5, 6);
printf("%d", g);
return 0;
}
foo.c
typedef struct{
int a;
int b;
char c;
char d;
} mystruct;
mystruct foo(int a, int b)
{
mystruct myl;
my.a = a;
my.b = a + 1;
my.c = (char) b;
my.d = (char b + 1;
return my1;
}
现在我首先使用 gcc 将 foo.c
编译为 foo.o
并检查符号 table 使用
readelf
并且我有一些名为 foo
同样在我将 main.c
编译为 main.o
之后检查了符号 table 并且它还有一些名为 foo
的条目,我将这两个链接在一起并且令人惊讶它工作了,我 运行 main.o
并且显然遇到了一些分段错误,这是有道理的,因为 foo.o
中实现的 foo
的实际实现可能需要三个参数(第一个应该是struct adders), 一个在foo
定义下未传入main.o
的参数,然后实际实现从main
的堆栈帧访问一些不属于它的内存,然后尝试访问它认为它获得的地址,并以分段错误结束,没关系,
现在我用 g++ 而不是 gcc 再次编译了两个模型,结果令人惊讶。我发现符号foo.o
下的条目是 _Z3fooii
,main.o
下的条目是 _Z3fooic
,现在我的猜测是 ii
后缀表示 int int
和 ic
后缀表示 int char
这可能是指应该传递给函数的参数,因此允许编译器知道一些函数减速得到实际实现。所以我将 main.c
中的 foo
声明更改为
extern int foo(int a, int b);
重新编译,这次得到了符号 _Z3fooii
,我再次链接了两个模型,令人惊讶的是这次它成功了,我尝试了 运行,但再次遇到了分段错误,这也使得感觉编译器甚至不会总是授权正确的 return 值..无论如何我最初的想法是什么 - g++ 在符号名称中包含函数签名,从而强制链接器提供函数实现获取正确的参数以更正函数声明