浅尝辄止23-Linux系统调用1

接着浅尝辄止21-Linux系统调用0,接着寻找pwrite的系统调用之路,线索就在浅尝辄止22-C语言属性-alias

pwrite的多个身份

执行git grep "alias.*pwrite",只关注Linux ARM32相关的就可以看到下面的关键信息。

sysdeps/unix/sysv/linux/pwrite.c:strong_alias (__libc_pwrite, __pwrite)
sysdeps/unix/sysv/linux/pwrite.c:weak_alias (__libc_pwrite, pwrite)

libc-symbols.h中可以找到如下信息,两种alias都是产生别名而已,只是其中一个是weak symbol。因此,我们可以知道__libc_pwrite,__pwritepwrite这些名字实际上是一回事。

/* Define ALIASNAME as a strong alias for NAME.  */
# define strong_alias(name, aliasname) _strong_alias(name, aliasname)
# define _strong_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((alias (#name)));
...
/* Define ALIASNAME as a weak alias for NAME.
   If weak aliases are not available, this defines a strong alias.  */
# define weak_alias(name, aliasname) _weak_alias (name, aliasname)
# define _weak_alias(name, aliasname) \
  extern __typeof (name) aliasname __attribute__ ((weak, alias (#name)));

pwrite的实现

进入pwrite.c看一下,pwrite的实现就靠一个宏SYSCALL_CANCEL

ssize_t
__libc_pwrite (int fd, const void *buf, size_t count, off_t offset)
{
  return SYSCALL_CANCEL (pwrite, fd, buf, count, SYSCALL_LL_PRW (offset));
}

SYSCALL_CANCEL的展开

根据libc-symbols.hsysdep.h中的定义,可以展开如下

SYSCALL_CANCEL (pwrite, fd, buf, count, SYSCALL_LL_PRW (offset))
=SYSCALL_CANCEL (pwrite, fd, buf, count, offset)
展开并去掉不关心的内容=>
INLINE_SYSCALL_CALL (pwrite, fd, buf, count, offset);
=>
__INLINE_SYSCALL_DISP (__INLINE_SYSCALL, pwrite, fd, buf, count, offset)
=>
__SYSCALL_CONCAT (__INLINE_SYSCALL,__INLINE_SYSCALL_NARGS(pwrite, fd, buf, count, offset))(pwrite, fd, buf, count, offset)
=>
__SYSCALL_CONCAT_X (__INLINE_SYSCALL, __INLINE_SYSCALL_NARGS(pwrite, fd, buf, count, offset))(pwrite, fd, buf, count, offset)
=>
__INLINE_SYSCALL__INLINE_SYSCALL_NARGS(pwrite, fd, buf, count, offset))(pwrite, fd, buf, count, offset)
=>
__INLINE_SYSCALL__INTERNAL_SYSCALL_NARGS_X (pwrite, fd, buf, count, offset,7,6,5,4,3,2,1,0,)(pwrite, fd, buf, count, offset)
=>
__INLINE_SYSCALL4(pwrite, fd, buf, count, offset)
=>
INLINE_SYSCALL (pwrite, 4, fd, buf, count, offset)
展开并去掉不关心的内容=>
INTERNAL_SYSCALL (pwrite, , 4, fd, buf, count, offset);
=>
INTERNAL_SYSCALL_RAW(SYS_ify(pwrite),  , 4, fd, buf, count, offset)
=>
INTERNAL_SYSCALL_RAW(__NR_pwrite,  , 4, fd, buf, count, offset)
=>
({                              \
       register int _a1 asm ("r0"), _nr asm ("r7");     \
       LOAD_ARGS_4 (fd, buf, count, offset)                 \
       _nr = __NR_pwrite;                       \
       asm volatile ("swi   0x0 @ syscall " "__NR_pwrite"   \
             : "=r" (_a1)               \
             : "r" (_nr) ASM_ARGS_4         \
             : "memory");               \
       _a1; })
=>
({                              \
       register int _a1 asm ("r0"), _nr asm ("r7");     \
       int _a4tmp = (int) (offset);         \
       int _a3tmp = (int) (count);            \
       int _a2tmp = (int) (buf);          \
       int _a1tmp = (int) (fd);         \
       _a1 = _a1tmp;                \
       register int _a2 asm ("buf") = _a2tmp;                \
       register int _a3 asm ("count") = _a3tmp;            \
       register int _a4 asm ("offset") = _a4tmp;                    \
       _nr = __NR_pwrite;                       \
       asm volatile ("swi   0x0 @ syscall " "__NR_pwrite"   \
             : "=r" (_a1)               \
             : "r" (_nr), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4)            \
             : "memory");               \
       _a1; })

最后这一大坨就是Linux ARM32的pwrite在glibc里面的最终实现了,下面逐行注释解说

//将{}用()包起来,这个括号就成了一个表达式,值就是最后面的表达式的值,即_a1
({                              \
//声明2个int型变量
//_a1用r0寄存器,用来传递系统调用的第一个参数
//_nr用r7寄存器,用来传递著名的系统调用号
       register int _a1 asm ("r0"), _nr asm ("r7");     \
//依次声明4个变量,分别将4个参数赋给它们
       int _a4tmp = (int) (offset);         \
       int _a3tmp = (int) (count);            \
       int _a2tmp = (int) (buf);          \
       int _a1tmp = (int) (fd);         \
//将第一个参数赋给寄存器r0
       _a1 = _a1tmp;                \
//将参数依次赋给寄存器,会顺次分配r1,r2,r3寄存器
       register int _a2 asm ("buf") = _a2tmp;                \
       register int _a3 asm ("count") = _a3tmp;            \
       register int _a4 asm ("offset") = _a4tmp;                    \
//将系统调用号__NR_pwrite给_nr
       _nr = __NR_pwrite;                       \
//以下四句gcc内联汇编
//swi 0x0,产生软件中断,这条指令就会触发内核的中断处理,从这条指令到内核中断处理,就是所谓的陷入内核过程了
//"=r" (_a1) 是将内联汇编的输出结果存到_a1,即系统调用的返回值
// "r" (_nr), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4) 是输入参数列表,会通过r7,r0,r1,r2,r3传递
// "memory"是被更改的资源,即内存有可能会被改变
       asm volatile ("swi   0x0 @ syscall " "__NR_pwrite"   \
             : "=r" (_a1)               \
             : "r" (_nr), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4)            \
             : "memory");               \
//内联汇编的输出结果会存到_a1,这就是这整个({...})表达式的值,即系统调用返回值
       _a1; })

__NR_pwrite是哪来的?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,226评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,509评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,523评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,181评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,189评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,642评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,993评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,977评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,527评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,547评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,661评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,991评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,422评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,571评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,241评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,737评论 2 366