ld and sopath and gdb useage

本文详细介绍了程序运行时如何查找所需共享库的具体步骤,包括环境变量LD_LIBRARY_PATH的作用、缓存文件/etc/ld.so.cache的内容及其优先级顺序,并提供了调试过程中设置gdbserver及远程调试的方法,以及32位库在64位Ubuntu系统中的安装路径。



1. so search path:

The necessary shared libraries needed by the program are  searched  for
       in the following order    

  a      Using      the      environment     variable     LD_LIBRARY_PATH

              (LD_AOUT_LIBRARY_PATH for a.out programs).  Except if  the  exe‐
              cutable is a setuid/setgid binary, in which case it is ignored.

  b      From  the  cache file /etc/ld.so.cache which contains a compiled
              list of candidate libraries previously found  in  the  augmented
              library  path.  Libraries  installed  in  hardware  capabilities
              directories (see below) are prefered to other libraries.

   c     In the default path /lib, and then /usr/lib.

2. see all the lib

cat /etc/ld.so.cache

 cat /etc/ld.so.conf (include /etc/ld.so.conf.d/*.conf)



3.gdb

a.

start gdb server

"/data/gdbserver :5039 --attach $p

//12345,tcp port; $p, pid


b. adb to tcp

adb forward tcp:5039 tcp:5039

//local port, remote port


c. connect to gdb server

target remote :5039


d. set so path

solib-search-path /XXX

mount -o remount,rw -t yaffs2 /dev/block/mtdblock1 /system
echo "|/system/bin/dd of=/sdcard/core-%e-%p-%t" >/proc/sys/kernel/core_pattern


4. lib for 32 in 64bit ubuntu

/lib/i386-linux-gnu


文件结构 Bash web_server/ ├── Makefile # 交叉编译配置 ├── web_server.c # 主程序入口 ├── server.h # 头文件 ├── process.c # 多进程实现 ├── thread.c # 多线程实现 ├── epoll.c # IO多路复用实现 ├── handler.c # 请求处理 └── static/ # Web文件目录 ├── index.html ├── style.css └── logo.png 1. 头文件 (server.h) C #ifndef SERVER_H #define SERVER_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/epoll.h> #include <sys/wait.h> #include <pthread.h> #include <dirent.h> // 服务器配置 #define PORT 8080 // 监听端口 #define BACKLOG 10 // 最大等待连接数 #define BUFFER_SIZE 4096 // 缓冲区大小 #define STATIC_DIR "./static" // Web文件目录 // 函数声明 void start_multi_process(int server_fd); void start_multi_thread(int server_fd); void start_epoll(int server_fd); void handle_request(int client_fd); void send_error(int client_fd, int code); const char *get_content_type(const char *path); #endif 2. 主程序 (web_server.c) C #include "server.h" int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s [process|thread|epoll]\n", argv[0]); exit(EXIT_FAILURE); } // 创建TCP套接字 int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket creation failed"); exit(EXIT_FAILURE); } // 配置服务器地址 struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(PORT) }; // 设置端口复用(避免"Address already in use"错误) int opt = 1; if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) { perror("setsockopt failed"); close(server_fd); exit(EXIT_FAILURE); } // 绑定端口 if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); } // 开始监听 if (listen(server_fd, BACKLOG) < 0) { perror("listen failed"); close(server_fd); exit(EXIT_FAILURE); } printf("Server running on port %d\n", PORT); printf("Web files directory: %s\n", STATIC_DIR); // 根据参数选择运行模式 if (strcmp(argv[1], "process") == 0) { start_multi_process(server_fd); } else if (strcmp(argv[1], "thread") == 0) { start_multi_thread(server_fd); } else if (strcmp(argv[1], "epoll") == 0) { start_epoll(server_fd); } else { fprintf(stderr, "Invalid mode. Use process, thread or epoll\n"); } close(server_fd); return 0; } 3. 多进程实现 (process.c) C #include "server.h" void start_multi_process(int server_fd) { printf("Running in multi-process mode\n"); while (1) { struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); // 接受客户端连接 int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len); if (client_fd < 0) { perror("accept failed"); continue; } // 创建子进程处理请求 pid_t pid = fork(); if (pid == 0) { // 子进程 close(server_fd); // 子进程不需要监听套接字 handle_request(client_fd); close(client_fd); exit(EXIT_SUCCESS); // 处理完成后退出 } else if (pid > 0) { // 父进程 close(client_fd); // 父进程不需要客户端套接字 waitpid(-1, NULL, WNOHANG); // 非阻塞回收僵尸进程 } else { perror("fork failed"); close(client_fd); } } } 4. 多线程实现 (thread.c) C #include "server.h" // 线程处理函数 void* thread_handler(void* arg) { int client_fd = *(int*)arg; free(arg); // 释放动态分配的内存 handle_request(client_fd); close(client_fd); return NULL; } void start_multi_thread(int server_fd) { printf("Running in multi-thread mode\n"); while (1) { struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); // 接受客户端连接 int *client_fd = malloc(sizeof(int)); if (!client_fd) { perror("malloc failed"); continue; } *client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len); if (*client_fd < 0) { free(client_fd); perror("accept failed"); continue; } // 创建线程处理请求 pthread_t tid; if (pthread_create(&tid, NULL, thread_handler, client_fd) != 0) { perror("pthread_create failed"); close(*client_fd); free(client_fd); } else { pthread_detach(tid); // 分离线程,自动回收资源 } } } 5. IO多路复用实现 (epoll.c) C #include "server.h" #define MAX_EVENTS 1024 void start_epoll(int server_fd) { printf("Running in epoll mode\n"); // 创建epoll实例 int epoll_fd = epoll_create1(0); if (epoll_fd < 0) { perror("epoll_create1 failed"); return; } // 添加服务器套接字到epoll struct epoll_event ev, events[MAX_EVENTS]; ev.events = EPOLLIN; ev.data.fd = server_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) { perror("epoll_ctl failed"); close(epoll_fd); return; } while (1) { // 等待事件 int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if (nfds < 0) { perror("epoll_wait failed"); continue; } for (int i = 0; i < nfds; i++) { if (events[i].data.fd == server_fd) { // 新连接 struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &len); if (client_fd < 0) { perror("accept failed"); continue; } // 设置非阻塞模式 fcntl(client_fd, F_SETFL, fcntl(client_fd, F_GETFL) | O_NONBLOCK); // 添加客户端到epoll ev.events = EPOLLIN | EPOLLET; // 边缘触发模式 ev.data.fd = client_fd; if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) { perror("epoll_ctl add client failed"); close(client_fd); } } else { // 客户端请求 handle_request(events[i].data.fd); // 移除并关闭客户端 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL); close(events[i].data.fd); } } } close(epoll_fd); } 6. 请求处理 (handler.c) C #include "server.h" void handle_request(int client_fd) { char buffer[BUFFER_SIZE]; ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1); if (bytes_read <= 0) { perror("read failed or connection closed"); return; } buffer[bytes_read] = '\0'; // 解析HTTP请求方法 (GET/POST等) char *method = strtok(buffer, " "); if (!method) { send_error(client_fd, 400); return; } // 只处理GET请求 if (strcmp(method, "GET") != 0) { send_error(client_fd, 501); // 501 Not Implemented return; } // 获取请求路径 char *path = strtok(NULL, " "); if (!path) { send_error(client_fd, 400); return; } // 安全过滤:防止路径遍历攻击 if (strstr(path, "..") || strstr(path, "//")) { send_error(client_fd, 403); // 403 Forbidden return; } // 处理默认路径 if (strcmp(path, "/") == 0) { path = "/index.html"; } // 构建完整文件路径 char full_path[256]; snprintf(full_path, sizeof(full_path), "%s%s", STATIC_DIR, path); // 检查文件是否存在 struct stat st; if (stat(full_path, &st) < 0) { send_error(client_fd, 404); return; } // 检查是否是目录 if (S_ISDIR(st.st_mode)) { // 如果是目录,尝试查找index.html char index_path[256]; snprintf(index_path, sizeof(index_path), "%s/index.html", full_path); if (stat(index_path, &st) < 0 || S_ISDIR(st.st_mode)) { send_error(client_fd, 403); // 目录浏览禁止 return; } strcpy(full_path, index_path); } // 打开文件 int fd = open(full_path, O_RDONLY); if (fd < 0) { perror("open file failed"); send_error(client_fd, 500); return; } // 获取内容类型 const char *content_type = get_content_type(full_path); // 构建HTTP响应头 char header[512]; int header_len = snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Server: SimpleWebServer\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" // 兼容IE8需要明确长度 "Connection: close\r\n\r\n", // 兼容IE8需要显式关闭 content_type, st.st_size); // 发送响应头 if (send(client_fd, header, header_len, 0) < 0) { perror("send header failed"); close(fd); return; } // 发送文件内容 ssize_t bytes, total_sent = 0; char file_buffer[BUFFER_SIZE]; while ((bytes = read(fd, file_buffer, BUFFER_SIZE)) > 0) { ssize_t sent = send(client_fd, file_buffer, bytes, 0); if (sent < 0) { perror("send file content failed"); break; } total_sent += sent; } close(fd); printf("Served: %s (%ld bytes)\n", path, total_sent); } // 根据文件扩展名获取内容类型 const char *get_content_type(const char *path) { const char *ext = strrchr(path, '.'); if (!ext) return "text/plain"; // 常见MIME类型映射 if (strcmp(ext, ".html") == 0) return "text/html; charset=utf-8"; if (strcmp(ext, ".htm") == 0) return "text/html; charset=utf-8"; if (strcmp(ext, ".css") == 0) return "text/css"; if (strcmp(ext, ".js") == 0) return "application/javascript"; if (strcmp(ext, ".json") == 0) return "application/json"; if (strcmp(ext, ".png") == 0) return "image/png"; if (strcmp(ext, ".jpg") == 0) return "image/jpeg"; if (strcmp(ext, ".jpeg") == 0) return "image/jpeg"; if (strcmp(ext, ".gif") == 0) return "image/gif"; if (strcmp(ext, ".ico") == 0) return "image/x-icon"; if (strcmp(ext, ".svg") == 0) return "image/svg+xml"; if (strcmp(ext, ".txt") == 0) return "text/plain; charset=utf-8"; return "application/octet-stream"; // 默认二进制流 } // 发送错误响应 void send_error(int client_fd, int code) { const char *messages[] = { [400] = "Bad Request", [403] = "Forbidden", [404] = "Not Found", [500] = "Internal Server Error", [501] = "Not Implemented" }; const char *message = messages[code] ? messages[code] : "Unknown Error"; char response[512]; int len = snprintf(response, sizeof(response), "HTTP/1.1 %d %s\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Connection: close\r\n\r\n" "<html><body><h1>%d %s</h1></body></html>", code, message, code, message); send(client_fd, response, len, 0); printf("Error %d: %s\n", code, message); } 7. Makefile 交叉编译配置 makefile # 交叉编译工具链配置 # 默认使用本地GCC,设置CROSS_COMPILE变量可切换交叉编译 CROSS_COMPILE ?= CC = $(CROSS_COMPILE)gcc CFLAGS = -Wall -Wextra -O2 -I. LDFLAGS = -lpthread # 目标文件列表 SRCS = web_server.c process.c thread.c epoll.c handler.c OBJS = $(SRCS:.c=.o) TARGET = web_server # 默认构建目标 all: $(TARGET) # 链接可执行文件 $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) # 编译C源文件 %.o: %.c $(CC) $(CFLAGS) -c $< -o $@ # 创建静态文件目录 static: mkdir -p static @echo "<html><body><h1>Hello from Web Server!</h1></body></html>" > static/index.html @echo "/* Sample CSS */ body { background: #f0f0f0; }" > static/style.css @echo "Static files created in static/ directory" # 交叉编译示例 (ARM架构) cross-arm: $(MAKE) CROSS_COMPILE=arm-linux-gnueabihf- # 清理构建文件 clean: rm -f $(OBJS) $(TARGET) # 安装到系统目录 (需要root权限) install: $(TARGET) cp $(TARGET) /usr/local/bin/ mkdir -p /var/www/static cp -r static/* /var/www/static/ .PHONY: all clean install static cross-arm 使用说明 编译服务器: Bash # 本地编译 make # ARM交叉编译 make cross-arm # 创建静态文件目录 make static 运行服务器: Bash # 多进程模式 ./web_server process # 多线程模式 ./web_server thread # epoll模式 ./web_server epoll对这个程序启动GDB调试
最新发布
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值