6、 静态库和共享库
静态库的编写通常如下:
cc -c -o foo.o goo.c
cc -c -o bar.o bar.c
ar ruv libfoo.a foo.o bar.o
查看库的内容:
ar tv libfoo.a
连接使用:cc -o baz baz.o -lfoo
而共享库的制作:
cc -fPIC -c -o foo.o foo.c
cc -fPIC -c -o bar.o bar.c
cc -shared -Wl,-soname, libfoo.so.0 -o libfoo.so foo.o bar.o
8、readelf 表示 ELF 文件信息
9、objdump 工具
11、用 objcopy 潜入可执行文件的数据
可以使用如下方式将 foo.jpg 转换为 x86 用的 ELF32 形式的目标文件 foo.o:
objcopy -I binary -O elf32-i386 -B i386 foo.jpg foo.o
然后
extern char _binary_foo_jpg_start[];
extern char _binary_foo_jpg_end[];
extern char _binary_foo_jpg_size[];
const char *start = _binary_foo_jpg_start;
const char *end = _binary_foo_jpg_end;
int size = (int)_binary_foo_jpg_size;
12 和 14、nm 命令的使用
-r 倒序输出
--size-sort 按符号所表示的对象大小从小到大排序
-S 输出对象大小
-f 指定格式:bsd,sysv,posix
-A 输出该符号被包含在哪个目标文件中:nm -A libc.a;nm -A *.o
strip 之后 nm 显示没有符号,用 -D 查动态库
nm foo.o | c++filt 或者 nm --demangle foo.o 转换 c++ 符号
15、add2line 从地址中获取文件名和行号
addr2line -f -e ADDR。
18、C 和 C++ 的互相调用
编译时带上 -dexceptions 选项
19、链接时的标识符冲突
20、PIC 编译
用 -fPIC 来编译共享库
21、statifier
将一个程序和对应所需的共享库制作成一个可执行文件,这样可以直接拿到别的机器上使用。
22、GNU 扩展入门
一些内置的函数 __built_in;
对函数声明时加上 attribute,对函数进行特殊优化。
int foo(int) __attribute__((attribute));
对于函数,attribute 可以包含如下内容:
constructor:调用 main 之前和加载共享目标时必须运行的函数。
23、gcc 中使用内联汇编
24、在 gcc built in 函数上的最优化
尽量使用 const 来修饰。
29、控制对外公开库的符号
31、在 main 前面调用函数
35、建成 PIE
42、GCC 安全编写入门
GCC 警告选项和 __attribute__ 的使用,环境变量 MALLOC_CHECK_ 在为 1 时继续运行,为 2 时立即终止。
43、用 ftrapv 检测整数溢出
有些情况无法检测
44, 45、用 Mudflap 和 -D_FORTIFY_SOURCE 检测缓冲区溢出
-g -fmudflap -lmudflap
还有个环境变量 MUDFLAP_OPTIONS 控制行为
47,48、位运算的问题
49、64 位下 0 和 NULL 的不同之处
NULL 并不是 0 这个 int 的值,带有 0 这个值的指针为 NULL。编译器必须要明白是用指针类型来解释的。
struct s *foo(const char *name, ...) { va_list va; struct s *sp; char *p; va_start(va, fmt); sp = (struct s*)malloc(sizeof(struct s)); if (!sp) return 0; memset(sp, '\0', sizeof(struct s)); set_name(sp, name); while((p=va_arg(va, char *))) { set_item(sp, p); } return sp; } ... sp = foo("foo", "bar", 0);
此程序据说在 64 位机器上无法正常运行。
只能如下使用 foo("foo", "bar", NULL);
51、注意信号处理函数中的非 volatile 和非 sig_atomic_t 型全局变量
不是所有函数都能被用在信号处理函数中,能从信号处理器安全的读出的函数称为“异步信号安全函数”。
52、用 sigwait 将异步信号进行同步处理
53、用 sigsafe 将信号处理安全化
60、LD_PRELOAD 更换共享库
63、C 的回溯(back trace)
backtrace() 和 backtrace_symbols_fd() 函数
64、检测运行中进程的路径名
readlink,getexecname,proc 文件系统
65、检测正在加载的共享库
dl_iterate_phdr 和 dlinfo
66、pmap 和进程的虚拟内存空间
67、用 libbfd 取得符号的一览表
68、运行 C++ 语言时进行 demangle
在运行时进行 demangle,一种是使用 binutils 的 libiberty 所包含的 cplus_demangle,另一种是使用包含在 libstdc++ 中的 abi::__cxa_demangle()。
70、用 libdwarf 取得调试信息
71、通过 dumper 简化 dump 出结构体的数据
利用 dumper 方便打印结构体的内容
76、用 sigaltstack 处理 stack overflow
77、面向函数的进入和退出的 hook
使用 GCC -finstrument-functions 选项,能调用面向函数的 enter 和 exit 时自生成的函数
78、从信号处理器中改写上下文
81、使用 SIGSEGV 来确认地址的有效性
#include <setjmp.h> #include <signal.h> #include <stdio.h> #define TRUE 1 #define FALSE 0 static struct sigaction orig_act; static sigjmp_buf env; static void sigsegv_handler(int sig) { siglongjmp(env, 1); } int validate(void *addr) { int is_valid = FALSE; struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = sigsegv_handler; sigaction(SIGSEGV, &act, &orig_act); if (sigsetjmp(env, TRUE) == 0) { volatile char c; c = *((char*)addr); *((char*)addr) = c; is_valid = TRUE; } else is_valid = FALSE; sigaction(SIGSEGV, &orig_act, NULL); return is_valid; } int main(int argc, char **argv) { int a; printf("variable a: %s\n", (validate(&a)?"valid":"invalid")); printf("100: %s\n", (validate((void *)100)?"valid":"invalid")); }
82,83:ltrace 和 strace
strace 用来 trace 系统调用
ltrace 用来跟踪系统调用共享库的函数
86、livepatch 在运行中的进程上发布补丁
87, 88,89:gprof,sysprof,oprofile 获取系统 profile。
获得系统整体 profile 的软件 —— sysprof,使用简单,功能有限。
oprofile 较复杂。
Related posts(相关文章):
好文章,强烈支持!
欢迎交换友情链接www.seonaut.org
您好,想和您做一些技术上的交流,望能加我,谢谢!qq :85937023
http://www.kdbj.net,http://www.chenyajun.com/ 博主换 友情链接么?