2583|1

176

帖子

3881

TA的资源

一粒金砂(高级)

楼主
 

kernel 花哨的编译连接技术 [复制链接]

转: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.


最新回复

这些玩意比较tricky,主要是为了少写汇编多写C,以增强可移植性,初学可以跳过去不看  详情 回复 发表于 2009-12-18 10:24

赞赏

1

查看全部赞赏

点赞 关注

回复
举报

1672

帖子

0

TA的资源

裸片初长成(初级)

沙发
 
这些玩意比较tricky,主要是为了少写汇编多写C,以增强可移植性,初学可以跳过去不看
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表