[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Do symbols make sense for C++



* Russ Allbery:

> I'm currently working on the Policy modification to document (and
> recommend) use of symbols instead of shlibs, but I'd only personally used
> symbols with C libraries.  Today I decided that I should try adding a
> symbols file to a C++ library, particularly if I'm going to recommend
> everyone do it.  I tried this exercise with xml-security-c, which is, I
> think, a reasonably typical C++ library.

Symbols just don't work for C++.  Large parts of a library ABI are not
expressed in terms of exported symbols.

Let's start with this:

struct Foo {
  long a;
  virtual void foo();
};

Foo *
f()
{
  return new Foo;
}

void
g(Foo *p)
{
  p->foo();
}

It is compiled to:

.globl _Z1gP3Foo
	.type	_Z1gP3Foo, @function
_Z1gP3Foo:
.LFB4:
	.cfi_startproc
	movq	(%rdi), %rax
	movq	(%rax), %rax
	jmp	*%rax
	.cfi_endproc
.LFE4:
	.size	_Z1gP3Foo, .-_Z1gP3Foo
	.p2align 4,,15
.globl _Z1fv
	.type	_Z1fv, @function
_Z1fv:
.LFB0:
	.cfi_startproc
	subq	$8, %rsp
	.cfi_def_cfa_offset 16
	movl	$16, %edi
	call	_Znwm
	movq	$_ZTV3Foo+16, (%rax)
	addq	$8, %rsp
	ret
	.cfi_endproc
.LFE0:
	.size	_Z1fv, .-_Z1fv

Now we threw new members to struct Foo and use Foo::bar() in g():

struct Foo {
  long a, b, c;
  virtual void foo();
  virtual void bar();
};

Foo *
f()
{
  return new Foo;
}

void
g(Foo *p)
{
  p->bar();
}

This does not change the symbols at all:

.globl _Z1gP3Foo
	.type	_Z1gP3Foo, @function
_Z1gP3Foo:
.LFB4:
	.cfi_startproc
	movq	(%rdi), %rax
	movq	8(%rax), %rax
	jmp	*%rax
	.cfi_endproc
.LFE4:
	.size	_Z1gP3Foo, .-_Z1gP3Foo
	.p2align 4,,15
.globl _Z1fv
	.type	_Z1fv, @function
_Z1fv:
.LFB0:
	.cfi_startproc
	subq	$8, %rsp
	.cfi_def_cfa_offset 16
	movl	$32, %edi
	call	_Znwm
	movq	$_ZTV3Foo+16, (%rax)
	addq	$8, %rsp
	ret
	.cfi_endproc
.LFE0:
	.size	_Z1fv, .-_Z1fv

Two constants change in an incompatible way, but the set of symbols
remains the same.  Of course, this is similar to C code where the size
of structs is not covered by symbol versioning, either.  For the Foo
struct itself, the size dependency can be hidden by only handing out
pointers to application code.  For Foo's vtable (which grows in size
to accommodate the Foo::bar() method), this is more difficult, and
downright impossible if application code needs to derive from Foo and
actually needs the method to be virtual.

In some isolated cases, symbols may still make sense for C++ (e.g., if
the library ABI is really stable and all you need to detect is use of
newly added classes to bump dependencies), but I don't think they work
in general.


Reply to: