dieyushi's Blog

ATOM Rss

下面是一些工作学习中总结的网络编程的方法。顺便提一句,又是一年没更新博客了,时间过的真快。

  • 一些手册一定要好好读一下,比如 proc(5), capabilities(7), icmp(7), ipv6(7), netlink(7), raw(7), socket(7), tcp(7), udp(7)
  • epoll 或者 select 处理事件时,可读事件时,read返回值-1,如果errno不为EAGAIN,可以认为失败,并关闭fd。read返回0,说明对方断开连接,此时也需要关闭fd。如果链路断了,如拔掉网线,需要是用keepalive来触发可写事件
Read More

写程序时经常会因为偷懒在syslog里面直接打10进制或者16进制的ip地址,又或者是数据库中保存的不是ip字符串,当看这些数据时每次都需要手算一些。为了提高效率,写了四个脚本,放到PATH里面就可以执行了。

#!/bin/bash
ip2hex () {
    local a b c d ip=$@
        IFS=. read -r a b c d <<< "$ip"
        printf '0x%x\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
}

ip2hex "$@"
#!/bin/bash
hex2ip () {
    local ip dec=$@
    desc=$(($desc))
        for e in {3..0}
    do
        ((octet = dec / (256 ** e) ))
            ((dec -= octet * 256 ** e))
            ip+=$delim$octet
            delim=.
            done
            printf '%s\n' "$ip"
}

hex2ip "$@"
#!/bin/bash
ip2dec () {
    local a b c d ip=$@
        IFS=. read -r a b c d <<< "$ip"
        printf '%d\n' "$((a * 256 ** 3 + b * 256 ** 2 + c * 256 + d))"
}

ip2dec "$@"
#!/bin/bash
dec2ip () {
    local ip dec=$@
        for e in {3..0}
    do
        ((octet = dec / (256 ** e) ))
            ((dec -= octet * 256 ** e))
            ip+=$delim$octet
            delim=.
            done
            printf '%s\n' "$ip"
}

dec2ip "$@"

测试

# ip2hex 1.2.3.4| xargs hex2ip | xargs ip2dec | xargs dec2ip
100.101.102.103
Read More

针对特定CPU进行一些优化工作时,就需要先对CPU支持的指令集进行判断。一般的做法是使用cpuid指令,然后检查相应的标识位来判断。这部分详见Intel的手册。

在使用中,发现了一个诡异的问题,如果在程序初始化时调用封装了cpuid的函数则正常运行,但是如果每次在使用使用优化函数前调用cpuid则会发生段错误。

挂上gdb启动程序,然后在段错误前si逐指令跟踪。最终确定原因为cpuid会将结果保存到RAX,RBX,RCX,RDX,问题就出到RBX上,根据Intel的文章

  • Registers RAX, RCX, RDX, R8, R9, R10, and R11 are considered volatile and must be considered destroyed on function calls.
  • RBX, RBP, RDI, RSI, R12, R14, R14, and R15 must be saved in any function using them.

如果gcc产生的指令使用到了RBX,我们又没有对RBX进行单独的保护,就会出现段错误。正确的调用cpuid方法是在使用cpuid前将RBX寄存器的值保存一下。

    movq %rbx, %r8
    movl $1, %eax
    cpuid
    xchgq %rbx, %r8
Read More

关于Linux内核模块加载时的版本检查,看了一些资料,记录一下。原文地址:http://www.skynet.ie/~mark/home/kernel/symbols.html

Exporting Symbols

By default, any global variables or functions defined in a module are exported to the kernel symbol table when the module is loaded. However, there are ways which you may control which symbols are exported.

If you only require that none of the module's symbols are exported you can use the EXPORT_NO_SYMBOLS macro.

If however, you require that only some of your global symbols are exported you will need to use the EXPORT_SYMBOL macro to export it. If CONFIG_MODVERSIONS is turned on a further step is required in the build process, but that will be explained later.

So How Does This Work?

A kernel module that explicitly exports symbols will have two special sections in its object file: the symbol table '_ksymtab' and the string table '.kstrtab'. When a symbol is exported by a module using EXPORTSYMBOL, two things happen:

  • a string, that is either the symbol name or, in the case that CONFIG_MODVERSIONS is turned on, the symbol name with some extra versioning info attached, is defined in the string table.

  • a module_symbol structure is defined in the symbol table. This structure contains a pointer to the symbol itself and a pointer to the entry in the string table.

When a module is loaded this info is added to the kernels symbol table and these symbols are now treated like any of the kernel's exported symbols.

To take a peek at your module's symbol table do

$> objdump --disassemble -j __ksymtab sunrpc.o

or the string table do

$> objdump --disassemble -j .kstrtab sunrpc.o

CONFIG_MODVERSIONS et al.

CONFIG_MODVERSIONS is a notion thought up to make people's lives easier. In essence, what it is meant to achieve is that if you have a module you can attempt to load that module into any kernel, safe in the knowledge that it will fail to load if any of the kernel data structures, types or functions that the module uses have changed.

If your kernel is not compiled with CONFIG_MODVERSIONS enabled you will only be able to load modules that were compiled specifically for that kernel version and that were also compiled without MODVERSIONS enabled.

However, if your kernel is compiled with CONFIG_MODVERSIONS enabled you will be able to load a module that was compiled for the same kernel version with MODVERSIONS turned off. But - here's the important part folks - you will also be able to load any modules compiled with MDOVERSIONS turned on, as long as the kernel API that the module uses hasn't changed.

So How Does This Work?

When CONFIG_MODVERSIONS is turned on the kernel then a special piece of versioning info is appended to every symbol exported using EXPORT_SYMBOL.

This versioning info is calculated using the genksyms command whose man page has this to say about how the info is calculated :

When a symbol table is found in the source, the symbol will be expanded to its full definition, where all struct's, unions, enums and typedefs will be expanded down to their basic part, recursively. This final string will then be used as input to a CRC algorithm that will give an integer that will change as soon as any of the included definitions changes, for this symbol.

The version information in the kernel normally looks like: symbol_R12345678, where 12345678 is the hexadecimal representation of the CRC. representation of the CRC.

What this means is that the versioning info is calculated in such way as that it will only change when the definition of that symbol changes.

The versioning string is 'appended' by the use of a #define in linux/modversions.h for every exported symbol. The #define usually winds up looking something like this (simplified):

#define printk printk_R1b7d4074

What this does is effectively get rid of the function 'printk' - alas, poor printk - and replace it with the much more handsome 'printk_R1b7d4074'.

If you have a look at linux/modversions.h you'll notice that it just includes loads of .ver files. These are generated using a command similar to

$> gcc -E -D__GENKSYMS__ ${c-file} | genksyms -k ${kernel-ver} > ${ver-file}

Notice that the c file if first passed through the c preprocessor before being passed to genksyms. This is to collapse all macros and stuff beforehand.

What does this mean for modules?

When modules are being compiled for a kernel with CONFIG_MODVERSIONS turned on, the header file linux/modversions.h must be included at the top of every c file. This you be an awful pain to do, so we just do it with the gcc flag '-include'.

   ifdef CONFIG_MODULES
   ifdef CONFIG_MODVERSIONS
   MODFLAGS += -DMODVERSIONS -include $(HPATH)/linux/modversions.h
   endif

The extra MODVERSIONS flag is used to indicate that this is a module being compiled with CONFIG_MODVERSIONS turned on as opposed to the kernel being compiled with CONFIG_MODVERSIONS enabled.

Read More

gdb常用的一些技巧

September 21 2014 , coding

最近一段时间遇到了几个定位了很长时间的bug,在定位过程中逐步学习了使用gdb,下面就是在调试中常用的一些调试方法。

1.条件断点

在for或者while中想要断在特定的值处, 人工不停的continue肯定是不现实的,这时就可以使用break if。

2. command

command可以设置在断点后执行一组gdb命令。
Read More