Reflect on some incompatible changes in GCC 10.

Starting with GCC10 and LTO enabled, current symbols
versioning hack does not work anymore. This patch
reflects on that and should be compatible with older
compilers that does not support __attribute__((symver))
yet.

Inspired by following code:
https://github.com/linux-rdma/rdma-core/blob/master/util/symver.h
This commit is contained in:
Ondrej Kozina
2021-04-06 17:22:28 +02:00
parent bc488fd4f1
commit e6089dd9c9
5 changed files with 129 additions and 24 deletions

View File

@@ -43,6 +43,7 @@ libcryptsetup_la_SOURCES = \
lib/nls.h \
lib/libcryptsetup.h \
lib/libcryptsetup_macros.h \
lib/libcryptsetup_symver.h \
lib/utils.c \
lib/utils_benchmark.c \
lib/utils_crypt.c \

View File

@@ -47,6 +47,7 @@
#include "libcryptsetup.h"
#include "libcryptsetup_macros.h"
#include "libcryptsetup_symver.h"
#define LOG_MAX_LEN 4096
#define MAX_DM_DEPS 32

105
lib/libcryptsetup_symver.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* Helpers for defining versioned symbols
*
* Copyright (C) 2021 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _LIBCRYPTSETUP_SYMVER_H
#define _LIBCRYPTSETUP_SYMVER_H
/*
* Note on usage:
*
* Do not use CRYPT_SYMBOL_EXPORT_NEW and CRYPT_SYMBOL_EXPORT_OLD on public
* symbols being exported only once. Linker will handle it automatically as
* always.
*
* It's supposed to be used only with symbols that are exported in at least
* two versions simultaneously as follows:
*
* - the latest version is marked with _NEW variant and oll other compatible
* symbols should be marked with _OLD variant
*
* Examples:
*
* - int crypt_func_X(unsigned *x, long y) gets introduced in CRYPTSETUP_2.4.
*
* No need to use any macro referenced here, just add proper version
* mapping in libcryptsetup.sym file.
*
* In later version CRYPTSETUP_2.5 symbol crypt_func_X has to fixed
* in incompatible way by adding new function parameter. The new version
* has to be added in mapping file libcryptsetup.sym as well.
*
* The definition of compatible function gets prefixed with following macro:
*
* CRYPT_SYMBOL_EXPORT_OLD(int, crypt_func_X, 2, 4,
* unsigned *x, long y)
* {
* function body
* }
*
* Whereas new version introduced in CRYPTSETUP_2.5 is defined as follows:
*
* CRYPT_SYMBOL_EXPORT_NEW(int, crypt_func_X, 2, 5,
* unsigned *x, long y, void *new_parameter)
* {
* function body
* }
*
* If in later version CRYPTSETUP_2.6 yet another version of crypt_func_X gets
* introduced it will be prefixed with CRYPT_SYMBOL_EXPORT_NEW(int, crypt_func_X, 2, 6...)
* macro and all previous versions CRYPTSETUP_2.4 and CRYPTSETUP_2.5 will be
* under CRYPT_SYMBOL_EXPORT_OLD(int, crypt_func_X, ...) macro
*/
#ifdef __has_attribute
# if __has_attribute(symver)
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
__attribute__((__symver__(#_public_sym _ver_str #_maj "." #_min)))
# endif
#endif
#if !defined(_CRYPT_SYMVER) && defined(__GNUC__)
# define _CRYPT_SYMVER(_local_sym, _public_sym, _ver_str, _maj, _min) \
asm(".symver " #_local_sym "," #_public_sym _ver_str #_maj "." #_min);
#endif
#define _CRYPT_FUNC(_public_sym, _prefix_str, _maj, _min, _ret, ...) \
_ret __##_public_sym##_v##_maj##_##_min(__VA_ARGS__); \
_CRYPT_SYMVER(__##_public_sym##_v##_maj##_##_min, _public_sym, _prefix_str "CRYPTSETUP_", _maj, _min) \
_ret __##_public_sym##_v##_maj##_##_min(__VA_ARGS__)
#ifdef _CRYPT_SYMVER
# define CRYPT_SYMBOL_EXPORT_OLD(_ret, _public_sym, _maj, _min, ...) \
_CRYPT_FUNC(_public_sym, "@", _maj, _min, _ret, __VA_ARGS__)
# define CRYPT_SYMBOL_EXPORT_NEW(_ret, _public_sym, _maj, _min, ...) \
_CRYPT_FUNC(_public_sym, "@@", _maj, _min, _ret, __VA_ARGS__)
#else /* no support for symbol versioning at all */
# define CRYPT_SYMBOL_EXPORT_OLD(_ret, _public_sym, _maj, _min, ...) \
static inline __attribute__((unused)) \
_ret __##_public_sym##_v##_maj##_##_min(__VA_ARGS__)
# define CRYPT_SYMBOL_EXPORT_NEW(_ret, _public_sym, _maj, _min, ...) \
_ret _public_sym(__VA_ARGS__)
#endif
#endif /* _LIBCRYPTSETUP_SYMVER_H */

View File

@@ -3325,7 +3325,9 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
return r;
}
int crypt_reencrypt(struct crypt_device *cd,
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_reencrypt, 2, 4,
/* crypt_reencrypt parameters follows */
struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr)
{
@@ -3388,18 +3390,13 @@ int crypt_reencrypt(struct crypt_device *cd,
return r;
}
#if defined(__GNUC__)
#define CRYPT_EXPORT_SYMBOL(func, maj, min) \
__asm__(".symver " #func "_v" #maj "_" #min ", " #func "@CRYPTSETUP_" #maj "." #min)
int crypt_reencrypt_v2_0(struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
int crypt_reencrypt_v2_0(struct crypt_device *cd,
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_reencrypt, 2, 0,
/* crypt_reencrypt parameters follows */
struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
{
return crypt_reencrypt(cd, progress, NULL);
}
CRYPT_EXPORT_SYMBOL(crypt_reencrypt, 2, 0);
#endif
static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr,

View File

@@ -2325,7 +2325,9 @@ static int _crypt_format(struct crypt_device *cd,
return r;
}
int crypt_format(struct crypt_device *cd,
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_format, 2, 4,
/* crypt_format parameters follows */
struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
@@ -2337,21 +2339,20 @@ int crypt_format(struct crypt_device *cd,
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, volume_key_size, params, true);
}
#if defined(__GNUC__)
#define CRYPT_EXPORT_SYMBOL(func, maj, min) \
__asm__(".symver " #func "_v" #maj "_" #min ", " #func "@CRYPTSETUP_" #maj "." #min)
int crypt_format_v2_0(struct crypt_device *cd, const char *type, const char *cipher,
const char *cipher_mode,const char *uuid, const char *volume_key,
size_t volume_key_size, void *params);
int crypt_format_v2_0(struct crypt_device *cd, const char *type, const char *cipher,
const char *cipher_mode,const char *uuid, const char *volume_key,
size_t volume_key_size, void *params)
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_format, 2, 0,
/* crypt_format parameters follows */
struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
const char *uuid,
const char *volume_key,
size_t volume_key_size,
void *params)
{
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, volume_key_size, params, false);
}
CRYPT_EXPORT_SYMBOL(crypt_format, 2, 0);
#endif
int crypt_repair(struct crypt_device *cd,
const char *requested_type,