标头和共享库之间不兼容的函数参数列表不会使我的程序崩溃,为什么?

问题描述 投票:0回答:1

当在两台不同的机器上构建我的大学项目时,我遇到了 LAPACK 和 Intel 在 MKL 中的实施问题。我已经找出了主要问题:我使用了

liblapacke-devel
中的 LAPACK 标头,这在两台机器之间有所不同。在其中一个标头中,每个 LAPACK 函数在参数列表末尾都有两个额外的
size_t
参数,其中包含某项。与 LAPACK 的 Fortran 起源有关。意识到这一点,并且由于我无论如何都链接到 MKL,所以我决定使用 MKL 标头,它们在参数列表中没有区别。

但是我很好奇,并尝试使用附加参数调用 LAPACK 函数之一 (

dsyev
),但仍然链接到 MKL,而 MKL 没有这些附加参数。我预计会出现段错误或类似错误,但我的测试程序运行得很好。可能是什么原因?

我的理论是,由于参数位于参数列表的末尾,因此当返回调用函数时它们不会被访问和清理。如果属实,这是否意味着做这样的事情就可以了,或者是否存在其他可能导致运行时问题的影响?在调用

dsyev
之前如何检查可能未对齐的堆栈?

我尝试了

objdump
nm
,却发现有关参数列表的信息从来都不是共享库的一部分,而只是符号名称的一部分。由于我缺乏使用
GDB
的经验,我也无法从那里提取任何有意义的信息。我怎样才能知道我的理论为什么仍然有效?


以下是

lapack.h
mkl_lapack.h
引用
dsyev_
的相关摘录,来自两个装置: 容器,来自
lapack.h
liblapacke-dev
,版本
3.10.0-2ubuntu1

...
/* It seems all current Fortran compilers put strlen at end.
*  Some historical compilers put strlen after the str argument
*  or make the str argument into a struct. */
#define LAPACK_FORTRAN_STRLEN_END
...
#define LAPACK_dsyev_base LAPACK_GLOBAL(dsyev,DSYEV)
void LAPACK_dsyev_base(
    char const* jobz, char const* uplo,
    lapack_int const* n,
    double* A, lapack_int const* lda,
    double* W,
    double* work, lapack_int const* lwork,
    lapack_int* info
#ifdef LAPACK_FORTRAN_STRLEN_END
    , size_t, size_t
#endif
);
#ifdef LAPACK_FORTRAN_STRLEN_END
    #define LAPACK_dsyev(...) LAPACK_dsyev_base(__VA_ARGS__, 1, 1)
#else
    #define LAPACK_dsyev(...) LAPACK_dsyev_base(__VA_ARGS__)
#endif

这会导致

dsyev
有两个额外的
size_t
参数,然后再次由
LAPACK_dsyev
定义处理。

主持人,

lapack.h
来自
liblapacke-dev
,版本
3.9.0-1build1

#define LAPACK_dsyev LAPACK_GLOBAL(dsyev,DSYEV)
void LAPACK_dsyev(
    char const* jobz, char const* uplo,
    lapack_int const* n,
    double* A, lapack_int const* lda,
    double* W,
    double* work, lapack_int const* lwork,
    lapack_int* info );

容器,

mkl_lapack.h
,来自
Intel OneMKL
,版本
2024.2

void DSYEV( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
            const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
            MKL_INT* info ) NOTHROW;
void dsyev( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
            const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
            MKL_INT* info ) NOTHROW;
void dsyev_( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
             const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
             MKL_INT* info ) NOTHROW;

(Capslock C 风格、C 风格、Fortran 风格)

主持人,

mkl_lapack.h
来自
Intel OneMKL
,版本
2021.1.1

void DSYEV( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
            const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
            MKL_INT* info ) NOTHROW;
void DSYEV_( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
             const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
             MKL_INT* info ) NOTHROW;
void dsyev( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
            const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
            MKL_INT* info ) NOTHROW;
void dsyev_( const char* jobz, const char* uplo, const MKL_INT* n, double* a,
             const MKL_INT* lda, double* w, double* work, const MKL_INT* lwork,
             MKL_INT* info ) NOTHROW;

(Capslock C 风格、Capslock Fortran 风格、C 风格、Fortran 风格)

c++ linker gdb lapack intel-mkl
1个回答
0
投票

我预计会出现段错误或类似错误,但我的测试程序运行得很好。

您的期望是不正确的。在这种情况下,工作正常是预期的行为。

可能是什么原因?

如果您阅读了有关调用约定的内容,您就会明白额外的参数是在附加寄存器(或堆栈上)中传递的。

调用者将这些参数放在那里,但被调用的例程只是从不查看它们(因为它不期望它们)。

因此唯一的影响是调用者执行不必要的操作并产生微小的开销。

© www.soinside.com 2019 - 2024. All rights reserved.