gun工具和自己写库

 


🔧 一、.so 动态库:从源码 → 编译 → 使用 完整闭环

1️⃣ 目录结构(从空白目录开始)

创建如下目录结构:

mkdir -p demo/{lib,include,src,app}
tree demo  # 查看结构(可选)

目录用途:

  • lib/:存放编译出的 .so动态库,如 libcalc.so

  • include/:存放头文件,如 calc.h

  • src/:存放库的源代码,如 calc.c

  • app/:存放调用该库的应用程序,如 main.c


2️⃣ 编写库的源码

📄 src/calc.c

#include "calc.h"
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }

📄 include/calc.h

#ifndef CALC_H
#define CALC_H
int add(int a, int b);
int sub(int a, int b);
#endif

3️⃣ 编译为位置无关的动态库 .so

进入项目根目录,执行:

cd demo
gcc -fPIC -shared src/calc.c -Iinclude -o lib/libcalc.so

✅ 验证编译结果:

file lib/libcalc.so        # 应输出 "shared object" 字样
nm -D lib/libcalc.so       # 应能看到 add 和 sub 符号

4️⃣ 编写调用动态库的程序

📄 app/main.c

#include <stdio.h>
#include "calc.h"

int main(void) {
    printf("10 + 5 = %d\n", add(10, 5));
    printf("10 - 5 = %d\n", sub(10, 5));
    return 0;
}

5️⃣ 编译应用程序并运行(多种方式)

进入 app 目录:

cd app

▶️ 方式①:使用 -L 和 -l 并通过 LD_LIBRARY_PATH 指定库路径

gcc main.c -I../include -L../lib -lcalc -o calc_demo

# 运行(临时指定库路径)
LD_LIBRARY_PATH=../lib ./calc_demo

▶️ 方式②:使用 rpath 打包库路径到可执行文件(推荐)

gcc main.c -I../include -L../lib -Wl,-rpath,'$ORIGIN/../lib' -lcalc -o calc_demo2

# 直接运行,无需每次设置环境变量
./calc_demo2

💡 注:$ORIGIN表示可执行文件所在目录,确保 ../lib/libcalc.so路径正确。

▶️ 方式③:将 .so 安装到系统库路径(需 root)

sudo cp ../lib/libcalc.so /usr/local/lib/
sudo ldconfig

# 然后直接运行(无需设置路径)
./calc_demo

6️⃣ 运行时手动加载 .so(使用 dlopen)

📄 app/dlopen_demo.c

#include <dlfcn.h>
#include <stdio.h>

int main(void) {
    void *h = dlopen("../lib/libcalc.so", RTLD_LAZY);
    if (!h) {
        fprintf(stderr, "dlopen error: %s\n", dlerror());
        return 1;
    }

    int (*add)(int, int) = dlsym(h, "add");
    int (*sub)(int, int) = dlsym(h, "sub");
    char *err;

    if ((err = dlerror()) != NULL) {
        fprintf(stderr, "dlsym (add/sub) err: %s\n", err);
        dlclose(h);
        return 1;
    }

    if (!add || !sub) {
        fprintf(stderr, "dlsym returned NULL for add/sub\n");
        dlclose(h);
        return 1;
    }

    printf("dlopen: 7 + 3 = %d\n", add(7, 3));
    printf("dlopen: 7 - 3 = %d\n", sub(7, 3));

    dlclose(h);
    return 0;
}

▶️ 编译并运行:

gcc dlopen_demo.c -ldl -o dlopen_demo
LD_LIBRARY_PATH=../lib ./dlopen_demo

⚙️ 二、KVM 内核模块:从源码 → 编译 → 加载 → 验证 完整闭环

✅ 适用场景:你手头有 ​​打过补丁的 KVM 源码目录​​(比如 kvm/kvm-next),想编译并替换系统自带 kvm 模块。


1️⃣ 安装编译依赖

sudo apt update
sudo apt install build-essential linux-headers-$(uname -r) \
    flex bison libssl-dev libelf-dev git bc

2️⃣ 获取 KVM 源码

方法①:从官方仓库克隆(推荐)

git clone git://git.kernel.org/pub/scm/virt/kvm/kvm.git
cd kvm

你也可以解压你自己修改过的源码包,进入对应目录即可。


3️⃣ 复用当前系统内核配置(推荐)

cp /boot/config-$(uname -r) .config
make olddefconfig  # 一路回车,保持默认选项

可选:如你只想快速编译 kvm 相关部分,而不是整个内核,可跳过冗余编译。


4️⃣ (可选)仅编译 kvm 目录对象文件(快速验证用)

make kvm/kvm.o

5️⃣ 编译 KVM 模块(重点!)

make -C /lib/modules/$(uname -r)/build M=$(pwd)/arch/x86/kvm modules

🔍 编译成功后,将在以下路径生成 .ko内核模块文件:

arch/x86/kvm/kvm.ko
arch/x86/kvm/kvm-intel.ko    # Intel CPU
arch/x86/kvm/kvm-amd.ko      # AMD CPU

✅ 你只需要关注当前 CPU 对应的模块,比如 Intel 用 kvm-intel.ko


6️⃣ 卸载旧模块,加载新编译的模块(必须 root)

⚠️ 如果你正在运行虚拟机,请先关闭!

sudo rmmod kvm_intel kvm_amd kvm   # 先卸载当前模块

然后加载新的:

# 通用核心模块
sudo insmod arch/x86/kvm/kvm.ko

# 根据你的 CPU 类型选择加载:
sudo insmod arch/x86/kvm/kvm-intel.ko   # Intel CPU
# 或者
sudo insmod arch/x86/kvm/kvm-amd.ko     # AMD CPU

7️⃣ 验证是否加载成功

lsmod | grep kvm
# 应该能看到 kvm、kvm_intel 或 kvm_amd,并且版本是你刚刚编译的

dmesg | tail -n 20
# 查看内核日志,可能会看到类似 "kvm: module loaded" 以及自定义信息

如果你打了补丁,可能 dmesg 中会有你的自定义打印信息,可用来验证是否为新模块。


8️⃣ (可选)永久替换系统模块

如果你希望每次启动都使用你编译的 KVM 模块,而不是系统自带的:

# 复制编译好的 .ko 文件到系统模块目录
sudo cp arch/x86/kvm/*.ko /lib/modules/$(uname -r)/kernel/arch/x86/kvm/

# 更新模块依赖
sudo depmod -a

# 设置开机自动加载(创建配置文件)
echo -e "kvm\nkvm-intel" | sudo tee /etc/modules-load.d/kvm.conf

# 重启系统
sudo reboot

重启后检查:

modinfo kvm           # 查看 vermagic 是否与你当前内核一致
lsmod | grep kvm

9️⃣ (可选)用 QEMU/Libvirt 启动虚拟机验证功能正常

安装必要组件:

sudo apt install qemu-kvm libvirt-daemon-system

查看虚拟机列表:

virsh list --all

创建并启动一个测试虚拟机(示例命令,可根据需求调整):

virt-install --name test --memory 1024 --vcpus 1 --disk none --boot cdrom --print-xml

只要能正常创建并启动虚拟机,就说明你的 KVM 模块工作正常 ✅


✅ 总结

功能

关键命令/步骤概要

​.so 动态库​

gcc -fPIC -shared-L -lLD_LIBRARY_PATHrpath/usr/local/lib+ ldconfigdlopen动态加载

​KVM 模块​

make modules生成 kvm.kokvm-intel.kormmod旧模块 → insmod新模块 → lsmod/dmesg验证 → 可永久替换到 /lib/modules


​GNU Binutils 工具速查表​​,涵盖 ​​nm、objdump、readelf、strip、ar、ranlib、size、strings、addr2line、gdb​​ 等最常用工具,按 ​​“一句话作用 + 最常用命令选项 + 典型输出示例”​​ 三栏清晰归纳,适合日常开发、逆向分析、二进制优化与调试快速查阅。


🛠 GNU Binutils 常用工具速查表(复制即用)

工具

一句话作用

最常用命令 & 必会选项

典型输出示例

​nm​

列出目标文件/库中的符号(函数、变量、地址)

nm -C a.out
nm -D libfoo.so(动态库符号)

0000000000401136 T main
0000000000601038 D global

​objdump​

反汇编二进制、查看段信息、重定位表等

objdump -d -M intel a.out(反汇编为 Intel 语法)
objdump -h a.out(查看段头)

4001136: 55 push rbp
...

​readelf​

查看 ELF 文件的详细结构(比 objdump 更细致)

readelf -S a.out(查看 Section 段表)
readelf -Ws a.out(查看符号表)

[ 1] .text PROGBITS ...
Symbol table '.symtab' contains ...

​strip​

删除符号表和调试信息,减小二进制体积

strip -s a.out(删除所有符号)
strip --strip-debug a.out(仅删调试信息)

文件体积显著变小(ls -lh对比)

​ar​

将多个 .o 目标文件打包成静态库 .a

ar rcs libmath.a add.o sub.o

生成静态库文件:libmath.a

​ranlib​

为静态库生成索引,加快链接速度(通常 ar rcs 已包含)

ranlib libmath.a

无输出,但后续链接更快

​size​

查看二进制各段(text/data/bss)占用空间大小

size a.out

text data bss dec hex filename
1234 56 78 1368 558 a.out

​strings​

提取二进制中可打印的字符串(常用于找线索/错误信息)

strings -n 6 a.out \| less(只显示长度≥6的字符串)

Hello world
Error: ...
...

​addr2line​

将地址转换为源码文件及行号(需编译时加 -g)

addr2line -e a.out 0x401136

/path/to/src/main.c:42

​gdb​

GNU 调试器,支持源码级调试、断点、回溯等

gdb ./a.out
常用内部命令:
break mainrunbt(查看调用栈)

源码级调试界面,支持逐行执行、查看变量、回溯调用栈等


🧪 速查示例脚本(一键运行体验所有工具)

以下脚本假设你已有一个 main.c源文件,且用 gcc -g编译为带调试信息的 demo可执行文件。

# 0. 编译一个带调试信息的可执行文件(如没有可自行准备)
gcc -g main.c -o demo

# 1. 查看符号表(找到 main 函数地址等信息)
nm -C demo | grep main

# 2. 反汇编,查看 main 函数汇编代码(Intel 语法)
objdump -d -M intel demo | grep -A5 '<main>'

# 3. 查看 ELF 文件的段表结构
readelf -S demo | head

# 4. 二进制瘦身:查看原大小 -> strip 后大小对比
ls -lh demo
strip -s demo
ls -lh demo  # 通常体积明显减小

# 5. 提取二进制中的字符串(比如查找隐藏的提示、错误信息等)
strings demo | grep -i error

# 6. 地址转源码行号(需确保编译带 -g,地址可从 crash log 或 objdump 中获取)
addr2line -e demo 0x401136

💡 一句话总结速记

​nm 看符号,objdump 读指令,readelf 读 ELF,strip 给二进制减肥,ar 打包静态库,ranlib 加速链接,size 查段大小,strings 挖字符串,addr2line 地址反推源码,gdb 调试神器​​ —— 其它工具按需查表即可!


🔧 本速查表适用于:

  • 🔍 二进制分析、逆向初探

  • 🛠 编译优化、瘦身、发布前处理

  • 🧩 调试崩溃、地址解析、符号查询

  • 📦 静态库打包与链接优化

  • 🧠 Linux 下 C/C++ 开发必备工具快速上手

 

posted on 2025-08-21 20:17  吃草的青蛙  阅读(26)  评论(0)    收藏  举报

导航