问题描述
感谢您阅读我的问题。
当我在 glibc 中调试 puts
函数时,我发现了一些无法理解的东西。
// glibc-2.27/libio/ioputs.c
int
_IO_puts (const char *str)
{
int result = EOF;
size_t len = strlen (str);
_IO_acquire_lock (stdout);
if ((_IO_vtable_offset (stdout) != 0
|| _IO_fwide (stdout,-1) == -1)
&& _IO_sputn (stdout,str,len) == len
&& _IO_putc_unlocked ('\n',stdout) != EOF)
result = MIN (INT_MAX,len + 1);
_IO_release_lock (stdout);
return result;
}
weak_alias (_IO_puts,puts)
如您所见,_IO_puts
调用 _IO_sputn
函数。
但是当我在 gdb 中检查 [r13+0x38] 时,有一个不同的值。
(不同的值)
-
_IO_file_jumps
在 glibc 中的作用是什么?
// glibc-2.27/libio/libioP.h
#define _IO_sputn(__fp,__s,__n) _IO_XSPUTN (__fp,__n)
// glibc-2.27/libio/libioP.h
typedef size_t (*_IO_xsputn_t) (FILE *FP,const void *DATA,size_t N);
#define _IO_XSPUTN(FP,DATA,N) JUMP2 (__xsputn,FP,N)
#define _IO_WXSPUTN(FP,N) WJUMP2 (__xsputn,N)
// glibc-2.27/libio/libioP.h
struct _IO_jump_t
{
JUMP_FIELD(size_t,__dummy);
JUMP_FIELD(size_t,__dummy2);
JUMP_FIELD(_IO_finish_t,__finish);
JUMP_FIELD(_IO_overflow_t,__overflow);
JUMP_FIELD(_IO_underflow_t,__underflow);
JUMP_FIELD(_IO_underflow_t,__uflow);
JUMP_FIELD(_IO_pbackfail_t,__pbackfail);
/* showmany */
JUMP_FIELD(_IO_xsputn_t,__xsputn);
JUMP_FIELD(_IO_xsgetn_t,__xsgetn);
JUMP_FIELD(_IO_seekoff_t,__seekoff);
JUMP_FIELD(_IO_seekpos_t,__seekpos);
JUMP_FIELD(_IO_setbuf_t,__setbuf);
JUMP_FIELD(_IO_sync_t,__sync);
JUMP_FIELD(_IO_doallocate_t,__doallocate);
JUMP_FIELD(_IO_read_t,__read);
JUMP_FIELD(_IO_write_t,__write);
JUMP_FIELD(_IO_seek_t,__seek);
JUMP_FIELD(_IO_close_t,__close);
JUMP_FIELD(_IO_stat_t,__stat);
JUMP_FIELD(_IO_showmanyc_t,__showmanyc);
JUMP_FIELD(_IO_imbue_t,__imbue);
};
这是我可以通过 ctags 和 cscope 找到的关于 _IO_sputn
的所有信息。
解决方法
为什么_IO_sputn函数是通过_IO_file_jumps调用的?
因为文件(“文件”作为对象)可能会以不同的方式实现放置字符,所以使用了调度表。
_IO_file_jumps 在 glibc 中的作用是什么?
它是一个 dispatch table - 一个函数指针数组。它用于指定一个通用的稳定虚拟接口,由不同的文件以不同的方式实现,这些文件需要为请求的操作提供不同的实现和抽象。
_IO_sputn 函数最终如何调用_IO_new_file_xsputn?
A function pointer 是 C 语言的一部分,它允许通过指向函数的指针调用另一个函数。 _IO_sputn
是一个 macro,它 expands 到 that function pointer 上的函数调用。宏用于简化将指向对象数据本身的指针传递给函数的过程——它不是特别漂亮,但简化了代码的编写。