Skip to content

Conversation

@yzewei
Copy link
Contributor

@yzewei yzewei commented Jan 8, 2026

Encountered Error: Symbol res_search not found when running the zaber_motion Python project (specifically while loading zaber-motion-core-linux-amd64.so).

The binary explicitly links against res_search, but on the host system (LoongArch64 with newer glibc), libresolv only exports __res_search. This PR adds a GO2 mapping to redirect the guest res_search to the host __res_search.

Reproduction

a minimal C program to reproduce the issue.

test_resolv.c:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <netinet/in.h>
#include <dlfcn.h>

#define TEST_START(name) printf("[-] Testing %s... ", name)
#define TEST_PASS() printf("PASS\n")
#define TEST_FAIL(msg) printf("FAIL: %s\n", msg)

typedef int (*b64_ntop_t)(unsigned char const *src, size_t srclength, char *target, size_t targsize);
typedef int (*b64_pton_t)(char const *src, unsigned char *target, size_t targsize);
typedef int (*dn_comp_t)(const char *src, unsigned char *dst, int dstsiz, unsigned char **dnptrs, unsigned char **lastdnptr);

void* load_hidden_sym(void* handle, const char* name) {
    void* sym = dlsym(handle, name);
    if (!sym) {
        printf("(Skip: symbol '%s' not found via dlsym) ", name);
        return NULL;
    }
    return sym;
}

void test_base64(void* lib_handle) {
    TEST_START("__b64_ntop / __b64_pton");
    
    b64_ntop_t my_b64_ntop = (b64_ntop_t)load_hidden_sym(lib_handle, "__b64_ntop");
    b64_pton_t my_b64_pton = (b64_pton_t)load_hidden_sym(lib_handle, "__b64_pton");

    if (!my_b64_ntop || !my_b64_pton) {
        printf("SKIPPED (Internal symbols missing)\n");
        return;
    }

    unsigned char src[] = "Box64";
    char encoded[64];
    unsigned char decoded[64];

    int len = my_b64_ntop(src, sizeof(src)-1, encoded, sizeof(encoded));
    if (len < 0) { TEST_FAIL("ntop failed"); return; }
    
    if (strstr(encoded, "Qm94NjQ=") == NULL) { TEST_FAIL("ntop output mismatch"); printf("   Got: %s\n", encoded); return; }

    int len2 = my_b64_pton(encoded, decoded, sizeof(decoded));
    if (len2 < 0) { TEST_FAIL("pton failed"); return; }
    decoded[len2] = '\0';
    
    if (strcmp((char*)decoded, "Box64") != 0) { TEST_FAIL("pton output mismatch"); return; }

    TEST_PASS();
}

void test_dn_comp_expand(void* lib_handle) {
    TEST_START("__dn_comp / dn_expand");
    
    dn_comp_t my_dn_comp = (dn_comp_t)load_hidden_sym(lib_handle, "__dn_comp");
    if (!my_dn_comp) {
        printf("SKIPPED (__dn_comp missing)\n");
        return;
    }

    unsigned char packet[128];
    int len = my_dn_comp("www.google.com", packet, sizeof(packet), NULL, NULL);
    if (len < 0) { TEST_FAIL("__dn_comp failed"); return; }

    char expanded[256];
    int res = dn_expand(packet, packet + len, packet, expanded, sizeof(expanded));
    
    if (res < 0) { TEST_FAIL("dn_expand failed"); return; }
    if (strcmp(expanded, "www.google.com") != 0) { 
        TEST_FAIL("Expansion mismatch"); 
        printf("   Got: %s\n", expanded);
        return; 
    }
    TEST_PASS();
}

void test_ns_get_put() {
    TEST_START("ns_put16 / ns_get16");
    unsigned char buf[16];
    
    ns_put16(12345, buf);
    unsigned int val = ns_get16(buf);
    
    if (val != 12345) {
        TEST_FAIL("Value mismatch");
        printf("   Expected 12345, got %u\n", val);
        return;
    }
    TEST_PASS();
}

void test_res_mkquery() {
    TEST_START("res_mkquery");
    unsigned char buf[4096];
    
    int len = res_mkquery(ns_o_query, "example.com", C_IN, T_A, NULL, 0, NULL, buf, sizeof(buf));
    
    if (len < 0) { TEST_FAIL("Returned < 0"); return; }
    TEST_PASS();
}

void test_res_query() {
    TEST_START("res_query (Checking symbol map)");
    unsigned char answer[4096];
    
    int len = res_query("google.com", C_IN, T_A, answer, sizeof(answer));
    
    if (len < 0) {
        printf("PASS (Network/Query fail is fine, symbol found)\n");
    } else {
        TEST_PASS();
    }
}

void test_res_search() {
    TEST_START("res_search (Your PR fix)");
    unsigned char answer[4096];
    
    int len = res_search("google.com", C_IN, T_A, answer, sizeof(answer));
    
    if (len < 0) {
        printf("PASS (Network/Query fail is fine, symbol found)\n");
    } else {
        TEST_PASS();
    }
}

void test_inet_net() {
    TEST_START("inet_net_pton");
    char *ip_str = "192.168.1.1";
    unsigned char buf[4];
    
    int bits = inet_net_pton(AF_INET, ip_str, buf, sizeof(buf));
    if (bits == -1) { TEST_FAIL("inet_net_pton failed"); } 
    else { TEST_PASS(); }
}

int main() {
    printf("=== Box64 libresolv Comprehensive Test (v2) ===\n");
    
    if (res_init() != 0) {
        printf("FATAL: res_init failed.\n");
        return 1;
    }

    void* handle = dlopen("libresolv.so.2", RTLD_LAZY);
    if (!handle) {
        handle = dlopen("libresolv.so", RTLD_LAZY);
    }
    if (!handle) {
        printf("Warning: Could not dlopen libresolv, skipping hidden symbol tests.\n");
    }

    test_base64(handle);
    test_ns_get_put();
    test_dn_comp_expand(handle);
    test_inet_net();
    test_res_mkquery();
    test_res_query();
    test_res_search();

    if (handle) dlclose(handle);
    printf("=== End of Tests ===\n");
    return 0;
}

Before Fix (Error):

[BOX64] Error: PltResolver: Symbol  res_search(optver 2: res_search@GLIBC_2.34) not found, cannot apply R_X86_64_JUMP_SLOT 0x100004000 in /home/yzw/python-trans/box_test/test_resolv_x64 (local_maplib=(nil), global maplib=0x3a762480, deepbind=0)
 return 0x100002038[function: (nil)]
 return 

After Fix (Success):

 test_resolv_x64
[BOX64] Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to the libs
[BOX64] Box64 loongarch64 v0.4.1 024b1837 with Dynarec built on Jan  8 2026 15:57:13
[BOX64] Dynarec for LoongArch with extension LSX LASX LBT_X86
[BOX64] Running on Loongson-3A5000LL with 4 cores, pagesize: 16384
[BOX64] Will use hardware counter measured at 2.3 GHz
[BOX64] Didn't detect 48bits of address space, considering it's 39bits
[BOX64] Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to the libs
[BOX64] Counted 63 Env var
[BOX64] Library search path: 
[BOX64] Binary search path: ./:bin/:/root/.cargo/bin/:/usr/local/python3.11/bin/:/usr/local/python3.6/bin/:/usr/local/jdk-11.0.9/bin/:/usr/local/jdk-11.0.9/bin/jar/:/home/yzw/bin/go//bin/:/usr/local/bin/:/usr/lib/golang-1.19/bin/:/usr/local/jdk-11.0.19/bin/:/usr/local/jdk-11.0.19/jre/bin/:/usr/share/Modules/bin/:/usr/local/sbin/:/usr/local/bin/:/usr/sbin/:/usr/bin/
[BOX64] Looking for ../../box_test/test_resolv_full
[BOX64] Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to the libs
[BOX64] Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to the libs
[BOX64] Dynarec for LoongArch with extension LSX LASX LBT_X86
[BOX64] Running on Loongson-3A5000LL with 4 cores, pagesize: 16384
[BOX64] Will use hardware counter measured at 2.3 GHz
[BOX64] BOX64ENV: Variables overridden:
	BOX64_ADDLIBS=/usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2
	BOX64_LOG=1
[BOX64] Rename process to "test_resolv_full"
[BOX64] BOX64, Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to needed libs of /home/yzw/python-trans/box_test/test_resolv_full
[BOX64] BOX64, Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to needed libs of /home/yzw/python-trans/box_test/test_resolv_full
[BOX64] BOX64, Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to needed libs of /home/yzw/python-trans/box_test/test_resolv_full
[BOX64] BOX64, Adding /usr/gnemul/latx-i386/lib/i386-linux-gnu/libresolv.so.2 to needed libs of /home/yzw/python-trans/box_test/test_resolv_full
[BOX64] Using native(wrapped) libresolv.so.2
[BOX64] Using native(wrapped) libc.so.6
[BOX64] Using native(wrapped) ld-linux-x86-64.so.2
[BOX64] Using native(wrapped) libpthread.so.0
[BOX64] Using native(wrapped) libdl.so.2
[BOX64] Using native(wrapped) libutil.so.1
[BOX64] Using native(wrapped) librt.so.1
[BOX64] Using native(wrapped) libbsd.so.0
=== Box64 libresolv Comprehensive Test (v2) ===
[-] Testing __b64_ntop / __b64_pton... PASS
[-] Testing ns_put16 / ns_get16... PASS
[-] Testing __dn_comp / dn_expand... PASS
[-] Testing inet_net_pton... PASS
[-] Testing res_mkquery... PASS
[-] Testing res_query (Checking symbol map)... PASS
[-] Testing res_search (Your PR fix)... PASS
=== End of Tests ===

@yzewei
Copy link
Contributor Author

yzewei commented Jan 8, 2026

PTAL!

Copy link
Collaborator

@ksco ksco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the proper way to address this, the old code is there for a reason.

So from what I can tell, on some systems, there is no res_search, and on some others, there is no __res_search. We can change the code to:

GOM(res_search, iFEpiipi)
GOM(__res_search, iFEpiipi)

And probe the available symbol using dlsym in my_res_search and my___res_search.

@yzewei
Copy link
Contributor Author

yzewei commented Jan 8, 2026

I don't think this is the proper way to address this, the old code is there for a reason.

So from what I can tell, on some systems, there is no res_search, and on some others, there is no __res_search. We can change the code to:

GOM(res_search, iFEpiipi)
GOM(__res_search, iFEpiipi)

And probe the available symbol using dlsym in my_res_search and my___res_search.

Hi,

I understand your point and agree with the approach. Before proceeding with dlsym to probe the availability of res_search and __res_search, I think it would be useful to first examine how many other function interfaces within the resolv library might be problematic in this context.

@ksco
Copy link
Collaborator

ksco commented Jan 8, 2026

Yeah, there are some similar ones indeed. Could use the same approach, sounds good.

Signed-off-by: yzewei <yangzewei@loongson.cn>
@yzewei yzewei changed the title [WRAPPER] Wrapped res_search symbol in libresolv [WRAPPER] Make libresolv symbols runtime-resolved (res_*/dn_expand) Jan 8, 2026
@ksco ksco requested a review from ptitSeb January 8, 2026 08:06
@yzewei
Copy link
Contributor Author

yzewei commented Jan 8, 2026

Thanks! @ksco

@ptitSeb ptitSeb merged commit 055a58d into ptitSeb:main Jan 8, 2026
27 checks passed
@xiangzhai
Copy link
Contributor

Thanks!

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.

4 participants