asm-offset.h 文件#
asm-offset.h 文件是在内核编译过程中生成的,生成过程 之前整理了一份笔记 TASK_threadsp的实现及asm-offsets.h, 其中涉及sed处理包含在内核代码 /scripts/Makefile.lib的sed-offsets中,工作是将生成的asm-offset.s转化为asm-offset.h。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| /scripts/Makefile.lib
...
# ASM offsets
# ---------------------------------------------------------------------------
# Default sed regexp - multiline due to syntax constraints
#
# Use [:space:] because LLVM's integrated assembler inserts <tab> around
# the .ascii directive whereas GCC keeps the <space> as-is.
define sed-offsets
's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \
/^->/{s:->#\(.*\):/* \1 */:; \
s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
s:->::; p;}'
endef
|
sed用法整理:#
s 命令(替代命令)是sed中最重要的一个命令,而且还支持很多不同选项,
- flags:
- **g:**替换所有匹配条目
- p: 打印 pattern space中的信息
- w filename:将结果输出到文件
正则表达式#
sed手册第5章对正则表达式有详细的描述,常见如下:
| 特殊字符 | 描述 |
|---|
| ^ | 匹配输入字符串开始的位置 |
| $ | 匹配输入字符串结尾的位置 |
| * | 匹配0个或多个在*之前的表达式 |
| \(regexp\) | 1. 后缀运算符符号, 如 \(abcd\)* 将寻找0个或多个“abcd”整个字符序列 2. 反向引用 |
| [list] | 匹配[]内的字符集合 |
| [^list] | 表示不匹配[]内的字符串 |
| .* | 匹配所有字符串,包含空 |
| .\+ | 匹配所有字符串,至少包含一个字符 |
| \$ | 匹配单个$符号 |
| [:alnum:] | 字母数字 |
| [:digit:] | 数字 |
| [:space:] | 制表符(\t) 换行符(\n) 垂直制表符(\v) 换页符(\f) 回车符(\r) 空格(\s)。 |
针对 Bracket Expressions , 如[:space:] , [:alnum:] 在使用时需要增加个[], 对sed新版本不增加的话会报错,对于老版本可以不加, 匹配的是[]中的集合, 非常幸运, 我的是老版本:),验证一下。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| ## 1. 输入1, 不包含在“:digit:”中直接输出
[root@centosgpt generate]# echo 1|sed ' s/[:digit:]/X/'
1
## 2. 输入d, 包含在“:digit:”中替换为X
[root@centosgpt generate]# echo d|sed ' s/[:digit:]/X/'
X
## 3. 修改正则表达式数字1被替换为X
[root@centosgpt generate]# echo 1|sed ' s/[[:digit:]]/X/'
X
## 4. 改为输入d, 匹配失败,输出X
[root@centosgpt generate]# echo d |sed ' s/[[:digit:]]/X/'
d
## 下面是sed手册里关于新版本Bracket Expressions为增加[]的报错信息
# current GNU sed versions - incorrect usage rejected
$ echo 1 | sed 's/[:digit:]/X/'
sed: character class syntax is [[:space:]], not [:space:]
|
#符号用来标识注释的开始
退出不再处理其他指令
删除模式空间,进入下一个周期
打印模式空间一般与-n一起使用 -n将不再自动输出pattern space
跳过单行
设置一组命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| ## 1. 使用q命令退出
[root@centosgpt generate]# seq 3| sed 2q
1
2
## 2. 使用d命令删除
[root@centosgpt generate]# seq 3| sed 2d
1
3
## 3. 使用n命令跳过使用p打印
[root@centosgpt generate]# seq 6|sed -n 'n;n;p'
3
6
|
sed-offsets分析:#
asm-offset.s片段:#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| .ascii "->"
# 0 "" 2
# 16 "asm-offsets.c" 1
.ascii "->#TASK_threadsp1"
# 0 "" 2
# 17 "asm-offsets.c" 1
.ascii "->TASK_threadsp1 $0 offsetof(struct task_struct1, thread.sp)"
# 0 "" 2
# 18 "asm-offsets.c" 1
.ascii "->"
# 0 "" 2
#NO_APP
|
sed-offsets处理过程:#
1
| 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:; \/^->/{s:->#\(.*\):/* \1 */:; \s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \s:->::; p;}'
|
1
| s:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:;
|
regexp部分分为6部分:
- ^[[:space:]]* 匹配0个或多个以空格,制表符,回车换行开头的行;
- \.ascii 匹配 “.ascii” 字符串;
- [[:space:]]* 匹配0个或多个以空格,制表符,回车换行符;
- "\(.*\)" 上面匹配成功后,该行后续双引号"“内部的字符串, 标记为引用 \1
- .* 匹配双引号后的任意字符串
- \1 引用regexp中原括号匹配的字符串
处理结果:
字符串“.ascii”对应的双引号内部的字符串替换本行如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| ## 1.command (由于使用-n 所以增加了一个p, 用于显示每步的输出)
#cat asm-offsets.s |sed -ne 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:;p'
## 2.output
->
# 0 "" 2
# 16 "asm-offsets.c" 1
->#TASK_threadsp1
# 0 "" 2
# 17 "asm-offsets.c" 1
->TASK_threadsp1 $0 offsetof(struct task_struct1, thread.sp)
# 0 "" 2
# 18 "asm-offsets.c" 1
->
# 0 "" 2
#NO_APP
|
1
| /^->/{s:->#\(.*\):/* \1 */:; \s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \s:->::; p;}'
|
设置”->#" 后的字符串设置为\1 ,并将\1内容放入注释段中
1
2
3
4
5
6
7
8
9
10
| ## 1.command (由于使用-n 所以增加了一个p, 用于显示每步的输出)
# cat asm-offsets.s |sed -ne 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:;/->/{s:->#\(.*\):/* \1 */:;p}'
## 2.output
->
/* TASK_threadsp1 */
->TASK_threadsp1 $0 offsetof(struct task_struct1, thread.sp)
->
|
1
| s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:;
|
regexp部分分为四部分:
- ->\([^ ]*\) 匹配将"->“开头的行,之后非空格的字符串做为第一个引用\1 ;
- [\$#]* \([^ ]*\) 跳过一个空格后,过滤$ ,#字符后非空格的字符串做为第一个引用\2;
- \(.*\) 跳过一个空格,后续所有字符串设置为引用
- :#define \1 \2 /* \3 */:; 组成C语言宏定义格式,并将\3 做为注释
1
2
3
4
5
6
7
8
9
10
| ## 1.command (由于使用-n 所以增加了一个p, 用于显示每步的输出)
# cat asm-offsets.s |sed -ne 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:;/->/{s:->#\(.*\):/* \1 */:;s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:;p}'
## 2.output
->
/* TASK_threadsp1 */
#define TASK_threadsp1 0 /* offsetof(struct task_struct1, thread.sp) */
->
|
过滤满足存在”->“行
1
2
3
4
5
6
7
| ## 1.command (由于使用-n 所以增加了一个p, 用于显示每步的输出)
#cat asm-offsets.s |sed -ne 's:^[[:space:]]*\.ascii[[:space:]]*"\(.*\)".*:\1:;/->/{s:->#\(.*\):/* \1 */:;s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:;s:->::;p}'
## 2.output
/* TASK_threadsp1 */
#define TASK_threadsp1 0 /* offsetof(struct task_struct1, thread.sp) */
|
将处理结果输出
1
| /* TASK_threadsp1 */#define TASK_threadsp1 0 /* offsetof(struct task_struct1, thread.sp) */
|
至此sed的任务顺利完成。
参考:#
sed, a stream editor
SED 简明教程
Sed - An Introduction and Tutorial by Bruce Barnett