taoyuetao的个人空间 https://blog.eetop.cn/taoyuetao [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

[随笔] 有关内核__setup的含义

已有 2511 次阅读| 2006-10-30 17:28 |个人分类:【 Linux & GNU 】

天气: 晴朗
心情: 高兴

================================

Author: taoyuetao
Email: tao_yuetao@yahoo.com.cn
Blog: http://www.eetop.cn/blog/?11145

================================

今天在网上看到一个比较有用的文章贴出来

关于__setup 在内核中的作用


你的这个问题,我从google上查找到了一些资料,再结合内核源代码,就在这里把这个问题说的清楚一点.
首先,这里有一个简短的回答,
http://mail.nl.linux.org/kernelnewbies/2003-03/msg00043.html

从这上面的意思是这里会从main.c 中的checksetup函数中运行,这个函数是这样的

static int __init checksetup(char *line)
{
struct kernel_param *p;

p = &__setup_start;
do {
int n = strlen(p->str);
if (!strncmp(line,p->str,n)) {
if (p->setup_func(line+n))
return 1;
}
p++;
} while (p < &__setup_end);
return 0;
}



这里的意思是从__setup_start开始处到__setup_end处中查找一个数据结构,这个数据结构中有str与setup_func这两个数据成员变量.
只要与这里面的str与输入的参数字符串相匹配,就会调用个这个字符串后面所指的内容,
对于你这里所说的 __setup("console=",console_setup); 就是你在启动linux内核的时候如果有这么一个参数输入console=ttyS1,那内核就会
把默认的tty定位为ttyS1,这个在consol_setup函数的字符串处理中完成,因为它最后是确定prefered_console的参数.


那把这在这里实现这个的内容是这样的,

__setup() 是一个宏定义,在include/linux/init.h这个文件中.
struct kernel_param {
const char *str;
int (*setup_func)(char *);
};

extern struct kernel_param __setup_start, __setup_end;

#define __setup(str, fn) \
static char __setup_str_##fn[] __initdata = str; \
static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }

在这个情景中作了替换是这样的

static char __setup_str_console_setup[] = "console=";
static struct kernel_param __setup_console_setup = { __setup_str_console_setup, console_setup}



这样你还可能不是很清楚,那你就要参考arch/i386/vmlinuz.lds这个关于ld 链接器的脚本文件有这样的一段

__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;


这里的意思就是__setup_start是一个节的开始,而__setup_end是一个节的结束,这个节的名称是.setup,init,
这个你可以用readelf -a这个来看一下你的vmlinux-2.4.20-8(后面的数字与你的内核版本有关)这个文件,
可以看到有一个叫.setup.init的节,__setup_start就是指这个节的开始,那这个节中有什么内容呢,其实就是一个
数据结构,一个就是str,一个就是setup_func,与我前面的说法相一致,那具体是什么呢,就是一个在.init.data节中存储的
字符串-----__initdata是一个宏,就是(__attribute__ ((__section__ (".data.init")))), 所以你可以.data.init在vmlinux-2.4.20-8中的
在文件中的偏移量与加载的的虚拟地址偏移量相减就可以得到,
举个例子,所有的这些都是用readelf 与od 命令得到的
我现在用的内核版本,它的.setup.init的节在0x26dd60的文件偏移处.
[10] .data.init PROGBITS c0368040 268040 005d18 00 WA 0 0 32
[11] .setup.init PROGBITS c036dd60 26dd60 0001b0 00 WA 0 0 4

再查找console_setup在vmlinux-2.4.20-8所被映射为内存地址,
840: c0355d40 343 FUNC LOCAL DEFAULT 9 console_setup

这就可以知道了它所在的位置,就是0xc0355d40,这就是它的虚拟映射地址

再用下面一条命令
od --address-radix=x -t x4 vmlinux-2.4.20-8 |grep -A 20 26dd60 |head -20 | grep c0355d40
可以得到
26de40 c036943b c0355d10 c0369447 c0355d40

很明显,这个函数的处理字符串在内存中的地址是0xc0369447,与前面得到的.data.init节在内存映射中的位置
0xc0368040相减就是 0x1407,与.data.init在文件中的偏移量0x268040相加就得到0x269447
这样用
od --address-radix=x -a vmlinux-2.4.20-8 |grep -A 2 269440

就可以得到下面的内容,
269440 b l i n k = nul c o n s o l e = nul
269450 r e s e r v e = nul nul nul nul nul nul nul nul
269460 ` dc4 6 @ ` dc4 6 @ c p u f r e q =

"console="这个值果真就在这里.

(注:前面od 的选项 --address-radix= 表示的是显示文件偏移量的格式,默认下是o就是八进制, -t 表示显示文件二进制的形式
默认是o6 就是八进制的6位长,而-a表示显示的是字符串格式.)

 


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 0

    粉丝
  • 0

    好友
  • 0

    获赞
  • 1075

    评论
  • 4435

    访问数
关闭

站长推荐 上一条 /2 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-24 14:57 , Processed in 0.034646 second(s), 14 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部