转:http://blog.chinaunix.net/u2/79526/showart.php?id=2121892
阅读linux的入门门槛在逐步提高, 看看这些技术的应用吧.
http://www.ohse.de/uwe/articles/gcc-attributes.html
我最先知道的编译连接是 pack(0),
#define __packed __attribute__((packed))
因为做网络通讯, 这个很常见. 用于将对齐改为1byte, 就是不要在结构内增加pad的内容. 可是打开linux源码看看, tcphdr竟然没有packed属性 , 真是雷阿.
(下面默认是32bit平台)
make V=1 net/ipv4/udp.o , 无线索. 没有-fpack-struct, 没有类似VC的-Zpn... 电话召唤wheel, 一起试验, 发现自己还是需要补充基础知识.
struct udphdr {
__be16 source;
__be16 dest;
__be16 len;
__sum16 check;
};
写程序, 打印sizeof udphdr, 可以发现这种声明是么有pad的. 规则是: char char short; short short long; long long (long long).
这个规则在各种平台(应该)通用. (否则mips上岂不是也要有问题阿)
令人惊奇的是: 下面的声明, sizeof值是1, 用做数组就会效率不高的. (一下在x86-32上验证, mips32上肯定不同,未试, )
struct udphdr {
char x;
};
而这个sizeof 是8
struct udphdr {
char x;
long x
};
最后这个sizeof 是4
struct udphdr {
char x;
short x
};
结论: 最可考的做法是测试下.
这篇可以参考下:
http://hi.baidu.com/phps/blog/item/f03eb93ee12f49fa838b1365.html
kernel image加载的逻辑地址, kernel image各段的起始/结束地址 init函数的收集, 这个都能在lds中找到. 不幸, lds文件找不到了....
find -iname *.lds
./arch/x86/boot/compressed/vmlinux_32.lds
./arch/x86/boot/compressed/vmlinux_64.lds
./arch/sh/boot/compressed/vmlinux_64.lds
./arch/mn10300/boot/compressed/vmlinux.lds
./arch/alpha/boot/bootloader.lds
./arch/ia64/hp/sim/boot/bootloader.lds
./arch/ia64/scripts/check-segrel.lds
./arch/ia64/module.lds
./arch/arm/boot/bootp/bootp.lds
./arch/m68k/kernel/vmlinux-std.lds
./arch/m68k/kernel/vmlinux-sun3.lds
./arch/m68k/kernel/module.lds
./arch/h8300/boot/compressed/vmlinux.lds
ft, 仔细看看 arch/kernle/目录, 原来变成了.lds.S, ft.
SECTIONS
{
. = LOAD_OFFSET + LOAD_PHYSICAL_ADDR;
.....
.initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
__initcall_start = .;
INITCALLS
__initcall_end = .;
}
}
好处是, 能够接受config配置的宏. 更灵活.
汇编文件手动定义调试信息 , 参考dwarf2.h.
采用宏来生成static inline 函数 , 这样, 一些函数的定义你有可能搜不到. 比如x86平台的readb writeb: x86/io.h
#define build_mmio_read (name, size, type, reg, barrier) \
static inline type name(const volatile void __iomem *addr) \
{ type ret; asm volatile("mov" size " %1,%0":reg (ret) \
:"m" (*(volatile type __force *)addr) barrier); return ret; }
build_mmio_read (readb, "b", unsigned char, "=q", :"memory")
build_mmio_read(readw, "w", unsigned short, "=r", :"memory")
build_mmio_read(readl, "l", unsigned int, "=r", :"memory")
采用WEAK 符号
汇编中采用WEAK宏, 定义在linux/linkage.h
#ifndef WEAK
#define WEAK(name) \
.weak name; \
name:
#endif
C中采用 attribute : linux/compiler-gcc.h
#define __weak __attribute__((weak))
在mips/kernle/timer.c中有个weak符号, 用于提供一个dummy的实现,
int __weak rtc_mips_set_time(unsigned long sec)
{
return 0;
}
在mips/sgi-ip22/ip22-time.c中可以提供一个非weak的符号覆盖weak符号, 用于提供特定平台的实现.
int rtc_mips_set_time(unsigned long tim)
{
struct rtc_time tm;
unsigned int save_control;
unsigned long flags;
rtc_time_to_tm(tim, &tm);
tm.tm_mon += 1; /* tm_mon starts at zero */
tm.tm_year -= 40;
....
}
然后, weak还可以和 alias配合, 嘿嘿, 门槛高阿.
发现一个有意思的属性: linux/compiler-gcc.h
#define __naked __attribute__((naked)) notrace
naked
Found in versions: 3.0-3.4 Description:
Use this attribute on the ARM, AVR, C4x and IP2K ports to indicate
that the specified function does not need prologue/epilogue
sequences generated by the compiler. It is up to the programmer
to provide these sequences.
赞赏
1
查看全部赞赏