Skip to content

Conditionally add uuid_time64 to sym. version map#3037

Merged
karelzak merged 1 commit intoutil-linux:masterfrom
nvinson:clang-17
May 22, 2024
Merged

Conditionally add uuid_time64 to sym. version map#3037
karelzak merged 1 commit intoutil-linux:masterfrom
nvinson:clang-17

Conversation

@nvinson
Copy link
Contributor

@nvinson nvinson commented May 13, 2024

The symbol uuid_time64 is conditionally defined. It only exists on 32-bit platforms that use the glibc library and enable support for the 64-bit time_t type.

For all other platforms, the symbol is undefined. As a result, when ld.lld version 17 or newer is used with default flags, ld.lld will reject the symbol map with the error:

version script assignment of 'UUID_2.40' to symbol 'uuid_time64'
failed: symbol not defined

To fix this issue, configure.ac and libuuid/src/Makemodule.am are updated to determine which version of the symbol map is needed, and supply the proper symbol map to ld.lld when linking.

fixes #3036
fixes Gentoo bug #931328

@nvinson nvinson closed this May 13, 2024
@nvinson nvinson reopened this May 13, 2024
@nvinson
Copy link
Contributor Author

nvinson commented May 13, 2024

As mentioned in bug #3036, an alternate approach is to add -Wl,--undefined-version to the linker flags. This would revert ld.lld to its former behavior and align with ld.bfd's.

Please let me know which method this project prefer.

@karelzak
Copy link
Collaborator

We need @thkukuk here :-)

The changes in the libuuid/src/Makemodule.am seems like overkill. you can specify the version-script more than once, so we can split the file to libuuid.sym and libuuid64.sym and do something like:

libuuid_la_LDFLAGS += $(VSCRIPT_LDFLAGS),$(top_srcdir)/libuuid/src/libuuid.sym
if HAVE_UUID_TIME64
libuuid_la_LDFLAGS += ,$(VSCRIPT_LDFLAGS),$(top_srcdir)/libuuid/src/libuuid64.sym 
endif

rather than generate the symbols file :-)

@thkukuk
Copy link
Contributor

thkukuk commented May 13, 2024

Maintaining two nearly identical symbol version maps will not work, people will forget quickly to adjust both files.
I never tried what will happen if you use two symbol version files, I'm a bit afraid of that the second overwrites the first one or about the "local" rule.
I couldn't find anything about this, looks like all projects and documentation work only with one symbol map. Would be interesting how other projects will solve this.
I have to play with this.

@thkukuk
Copy link
Contributor

thkukuk commented May 13, 2024

Maybe instead of playing around with two symbol version files, we could use:
__asm__(".symver uuid_time64,uuid_time64@UUID_2.40");?

@thkukuk
Copy link
Contributor

thkukuk commented May 13, 2024

Using two symbol files does not work if they specify the same version tags.
So either we use __asm__ or another idea: build the symbol version map with help of cpp or grep (grep -v uuid_time64 *.map to remove the entry).

@karelzak
Copy link
Collaborator

It's interesting, but it works to split the version script into more files and ld generates from all the files one map.

I have tried:

libuuid_la_LDFLAGS += $(VSCRIPT_LDFLAGS),$(top_srcdir)/libuuid/src/libuuid.sym \
+                     $(VSCRIPT_LDFLAGS),$(top_srcdir)/libuuid/src/libuuid-foo.sym

and make uuidgen V=1 returns:

-g -O2 -Wl,--version-script -Wl,./libuuid/src/libuuid.sym -Wl,--version-script -Wl,./libuuid/src/libuuid-foo.sym

and readelf -a .libs/libuuid.so.1:

Version definition section '.gnu.version_d' contains 7 entries:
 Addr: 0x0000000000001338  Offset: 0x00001338  Link: 5 (.dynstr)
  000000: Rev: 1  Flags: BASE  Index: 1  Cnt: 1  Name: libuuid.so.1
  0x001c: Rev: 1  Flags: none  Index: 2  Cnt: 1  Name: UUID_1.0
  0x0038: Rev: 1  Flags: none  Index: 3  Cnt: 2  Name: UUID_2.20
  0x0054: Parent 1: UUID_1.0
  0x005c: Rev: 1  Flags: none  Index: 4  Cnt: 2  Name: UUID_2.31
  0x0078: Parent 1: UUID_2.20
  0x0080: Rev: 1  Flags: none  Index: 5  Cnt: 2  Name: UUID_2.36
  0x009c: Parent 1: UUID_2.31
  0x00a4: Rev: 1  Flags: none  Index: 6  Cnt: 2  Name: UUID_2.40
  0x00c0: Parent 1: UUID_2.36
  0x00c8: Rev: 1  Flags: none  Index: 7  Cnt: 1  Name: UUIDD_PRIVATE

but libuuid.sym is only UUID_1.0, and libuuid-foo.sym is the rest.

I guess it was designed for situations when you need to maintain each version on a separate file.

It does not mean we need to use it; just want to share what I learned today :-))

The situation is so special that I think using __asm__(".symver uuid_time64,uuid_time64@UUID_2.40") is fine if it is portable. It reduces changes in build-system(s).

@thkukuk
Copy link
Contributor

thkukuk commented May 13, 2024

The __asm__ directive seems to get overwritten by the symbol map file :(

| but libuuid.sym is only UUID_1.0, and libuuid-foo.sym is the rest.
That's why it could work: UUID_2.40 is only used for uuid_time64 in util-linux, so we don't have the problem with the duplicate version tag.

@t-8ch
Copy link
Member

t-8ch commented May 13, 2024

What about using a glob in the version file: uuid_time64*?

@karelzak
Copy link
Collaborator

The __asm__ directive seems to get overwritten by the symbol map file :(

What does it mean? There is only uuid_time64 in 2_40. We can skip this version in the map file. Or does the file force the linker to completely ignore asm directives?

Would it be possible to have always defined uuid_time64()?

@thkukuk
Copy link
Contributor

thkukuk commented May 13, 2024

The __asm__ directive seems to get overwritten by the symbol map file :(

What does it mean? There is only uuid_time64 in 2_40. We can skip this version in the map file. Or does the file force the linker to completely ignore asm directives?

Looks like the local rule in the map file overwrites the asm directive. But I haven't looked yet deeper at it, if not possible or a bug in my tests.

Would it be possible to have always defined uuid_time64()?

That should be possible.

I will try to look at this on Wednesday earliest.

@thesamesam
Copy link
Contributor

I'm a bit late, but the asm symver thing is usually a problem as it breaks with LTO.

@karelzak
Copy link
Collaborator

Also note: #3013

@thkukuk
Copy link
Contributor

thkukuk commented May 15, 2024

About always adding uuid_time64(): what about pure 32bit architectures, which have no time64_t? We could add a dummy uuid_time64 here, too, but since there is no error handling, I don't like that idea. Could lead other developers to do stupid ideas.
And then we have musl libc, where time_t is time64_t and thus we also have no uuid_time64() function.
Adding the missing uuid_time64() correct in all cases will be really complex.

About multiple version scripts: all documentation is always speaking about one version script, I couldn't find anything about specifying multiple one. I'm waiting now for feedback from some ld developers.

@t-8ch
Copy link
Member

t-8ch commented May 15, 2024

For me the glob uuid_time* works nicely.
If the symbol does not exist, lld will just ignore it.

It would prevent us from adding new symbols with the prefix uuid_time64, but that seems like a reasonable tradeoff.

@karelzak
Copy link
Collaborator

I didn't try glob uuid_time64*, but if it works, we can use it. It seems like a pretty minimalistic change.

It's strange that there is not any "good practice" to do such a thing. It seems like we reinventing the wheel :-)

@thkukuk
Copy link
Contributor

thkukuk commented May 15, 2024

I didn't try glob uuid_time64*, but if it works, we can use it. It seems like a pretty minimalistic change.

uuid_time*, not uuid_time64*. I doubt that the later will solve the problem.

It's strange that there is not any "good practice" to do such a thing. It seems like we reinventing the wheel :-)

As this was not an error until now from ld, I'm afraid the big wave with bug reports is now only coming. It's only the second report I saw now, but I'm aware of many more projects with functions which are not always available.

@nvinson
Copy link
Contributor Author

nvinson commented May 15, 2024

uuid_time*, not uuid_time64*. I doubt that the later will solve the problem.

uuid_time64* does work. I'll update the PR to make only that change.

The symbol uuid_time64 is conditionally defined. It only exists on
32-bit platforms that use the glibc library and enable support for
the 64-bit time_t type.

For all other platforms, the symbol is undefined. As a result, when
ld.lld version 17 or newer is used with default flags, ld.lld will
reject the symbol map with the error:

    version script assignment of 'UUID_2.40' to symbol 'uuid_time64'
    failed: symbol not defined

To fix this issue, the reference to uuid_time64 is changed to
uuid_time64*. The change to a glob pattern satisifies ld.lld and allows
the library to link.

fixes util-linux#3036
fixes Gentoo bug #931328

Signed-off-by: Nicholas Vinson <[email protected]>
@nvinson
Copy link
Contributor Author

nvinson commented May 20, 2024

If there are no other changes requested, could this PR be merged?

Thanks.

@karelzak karelzak merged commit 6a865db into util-linux:master May 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2.40.1 - ld.lld: error: version script assignment of 'UUID_2.40' to symbol 'uuid_time64' failed: symbol not defined

5 participants