#include
int main() {
int a = 3;
int b = 5;
int c = 7;
printf("%d",(a + b) * c);
return 0;
}
把上面程序使用gcc编译之后,默认得到的文件名为a.out[vagrant@10 04]$ ldd a.out
linux-vdso.so.1 => (0x00007ffe6d5f8000)
libc.so.6 => /usr/lib64/libc.so.6 (0x00007f476d62d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f476d9fa000)
ldd模拟运行一遍程序,在运行过程中做动态链接,从而得知这个可执行文件依赖于哪些共享库,每个共享库都在什么路径下,加载到进程地址空间的什么地址。也就是说我们使用gcc编译器编译的时候规定动态链接的是/usr/lib64/libc.so.6[vagrant@10 04]$ readelf -h /usr/lib64/libc.so.6
ELF 头:
Magic: 7f 45 4c 46 02 01 01 03 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - GNU
ABI Version: 0
Type: DYN (共享目标文件)
Machine: Advanced Micro Devices X86-64
Version: 0x1
入口点地址: 0x224e0
程序头起点: 64 (bytes into file)
Start of section headers: 2146808 (bytes into file)
标志: 0x0
本头的大小: 64 (字节)
程序头大小: 56 (字节)
Number of program headers: 10
节头大小: 64 (字节)
节头数量: 76
字符串表索引节头: 75
可以看到该共享库支持的操作系统(OS)是UNIX,应用程序二进制接口(ABI)是GNU。所以我们去看下gnu的printf的源码实现
找了个最老的版本,看了下,太复杂。。/*
* linux/lib/write.c
*
* (C) 1991 Linus Torvalds
*/
#define __LIBRARY__
#include
_syscall3(int,write,int,fd,const char *,buf,off_t,count)// 路径在 include/unistd.h
#define _syscall3(type,name,atype,a,btype,b,ctype,c) \
type name(atype a,btype b,ctype c) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \
if (__res>=0) \
return (type) __res; \
errno=-__res; \
return -1; \
}
疑惑点
lib不是内核的代码吗,不应该在进入内核前中断么,怎么是先进入的内核然后才触发中断呢?
原来lib目录本身也有Makefile会生成一个静态库。