当前位置: 首页 > 知识库问答 >
问题:

JDK-18 外来函数:如何使用具有相同名称但来自不同本机库的多个函数?

连翰
2023-03-14

假设我加载了一个具有函数get_gg()的本机库gg3,并且想要加载另一个也具有get_gg()函数的本机库gg4 - 我如何以“库感知”方式查找一个(例如,在某些情况下使用gg4中的get_gg(),否则使用gg3中的get_gg)?

我尝试了CLinker.systemCLinker().lookup(),但这似乎只是获取在加载的本机库中找到的第一个符号。

内部类中搜索后,我发现SystemLookup.libLookup()似乎很有希望但不公开,因此我实现了一个类似的方法来查找加载的本机库:

private static SymbolLookup libLookup(Function<NativeLibraries, NativeLibrary> loader) {
        NativeLibrary lib = loader.apply(NativeLibraries.rawNativeLibraries(SystemLookup.class, false));
        return name -> {
            Objects.requireNonNull(name);
            try {
                long addr = lib.lookup(name);
                return addr == 0 ?
                        Optional.empty() :
                        Optional.of(NativeSymbol.ofAddress(name, MemoryAddress.ofLong(addr), ResourceScope.globalScope()));
            } catch (NoSuchMethodException e) {
                return Optional.empty();
            }
        };
    }

然而,这显然是被禁止的,因为我不能从另一个类装入器装入库(我不知道最初使用的是哪个类装入器):

java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader

所以我怎样才能找到

共有1个答案

崔恺
2023-03-14

FWIW,完成这项工作所需的API在19年公开

在此之前,建议是通过绑定dlopendlclodlsym(或Windows等价物)来手动实现它以加载库并查找符号。

e、 g.在我的Windows计算机上:

public class Main {
    
    static final MethodHandle MH_LoadLibraryA;
    static final MethodHandle MH_FreeLibrary;
    static final MethodHandle MH_GetProcAddress;

    static {
        System.loadLibrary("Kernel32");
        SymbolLookup lookup = SymbolLookup.loaderLookup();
        CLinker linker = CLinker.systemCLinker();
        MH_LoadLibraryA = linker.downcallHandle(
            lookup.lookup("LoadLibraryA").orElseThrow(),
            FunctionDescriptor.of(ADDRESS, ADDRESS));
        MH_FreeLibrary = linker.downcallHandle(
            lookup.lookup("FreeLibrary").orElseThrow(),
            FunctionDescriptor.of(JAVA_INT, ADDRESS));
        MH_GetProcAddress = linker.downcallHandle(
            lookup.lookup("GetProcAddress").orElseThrow(),
            FunctionDescriptor.of(ADDRESS, ADDRESS, ADDRESS));
    }

    static MemoryAddress LoadLibraryA(String name) {
        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
            return (MemoryAddress) MH_LoadLibraryA.invokeExact((Addressable) allocator.allocateUtf8String(name));
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    static boolean FreeLibrary(MemoryAddress handle) {
        try {
            return ((int) MH_FreeLibrary.invokeExact((Addressable) handle)) != 0;
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    static MemoryAddress GetProcAddress(MemoryAddress handle, String name) {
        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SegmentAllocator allocator = SegmentAllocator.nativeAllocator(scope);
            return (MemoryAddress) MH_GetProcAddress.invokeExact((Addressable) handle, (Addressable) allocator.allocateUtf8String(name));
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }
    
    static SymbolLookup libraryLookup(String libraryName, ResourceScope scope) {
        MemoryAddress handle = LoadLibraryA(libraryName);
        if (handle == MemoryAddress.NULL) {
            throw new IllegalArgumentException("Cannot find library: " + libraryName);
        }
        scope.addCloseAction(() -> FreeLibrary(handle));
        return name -> {
            var addr = GetProcAddress(handle, name);
            return addr == MemoryAddress.NULL ?
                Optional.empty() : Optional.of(NativeSymbol.ofAddress(name, addr, scope));
        };
    }

    public static void main(String[] args) throws Throwable {
        try (ResourceScope scope = ResourceScope.newConfinedScope()) {
            SymbolLookup lookup = libraryLookup("gg", scope);
            MethodHandle handle = CLinker.systemCLinker().downcallHandle(
                lookup.lookup("get_gg").orElseThrow(),
                FunctionDescriptor.of(JAVA_INT));
            int x = (int) handle.invoke();
            System.out.println(x);
        }
    }
}
 类似资料:
  • 问题内容: 表1包含列:entry_id user_id …表2包含列:entry_id user_id … user_id条目并不总是相同的,因此我想将它们都提取出来,以便以后可以在脚本中对它们进行比较 我想提取t1.user_id和t2.user_id …问题是结果数组只有user_id 谢谢你 问题答案: 使用关键字:

  • 问题内容: 我正在尝试获得类似这样的功能的参考: 我有以下错误: 如何获得具有指定参数的功能? 问题答案: 由于有两个名称相同但签名不同的方法,因此您必须指定所需的方法: 或者(如@Antonio正确指出的): 如果您需要将类的实例作为第一个参数的咖喱函数,则可以以相同的方式进行,只有签名不同(将@Antonios注释与您的问题进行比较):

  • 问题内容: 我的问题是为什么我不能再次调用该函数?或者,如何做到这一点? 假设我有这个功能: 我称之为: 我得到4。 但是,假设我声明了一个与该函数同名的变量(错误): 现在,如果我尝试这样做: 要么: 我将收到此错误:“ TypeError:’int’对象不可调用” 无法将变量“ a”分配给函数? 问题答案: 完成此操作后: 不再是一个 函数 ,而只是一个 整数 (您已将其重新分配!)。因此,很

  • 问题内容: 我在通过JPA使用sql本机查询选择某些数据时遇到了一些麻烦。那是因为我有3个名称相同的列“ descricao”。 当我通过 EntityManager 接口的 createNativeQuery 方法执行select操作时,找到的第一列值将覆盖其他值。 (例如,当我在一个对象数组中得到此结果时,给定记录的第一列描述的值为“ foo”,第二个“ bar”和第三个“ foobar”(因

  • 问题内容: 我想解析一个json文件,但它经过这样的事情: 但是大约有三千个这样的对象。我一直在使用Gson解析我的json对象,但是我怎么解析这种文件呢?以及如何检索名称“ CDG”或“ ORY”? 问题答案: 您可以尝试如下操作: 使用gson,您可以按以下方式检索键名: 并使用java- json 可以执行以下操作: 从网址获取json:

  • 问题内容: 我有一张供用户使用的表。但是,当用户对其个人资料进行任何更改时,我会将它们存储在临时表中,直到我批准它们为止。然后将数据复制到活动表中,并从临时表中删除。 我想要实现的是,在管理面板中或用户可以在提交前仔细检查的页面中查看数据时,我想编写一个查询,该查询将允许我从两个表中获取ID为ID的表中的数据两者都等于$ userid。然后,我想以表格形式显示它们,其中旧值显示在左列中,而新值显示