Aiur – ZelluX 的技术博客

Security, Kernel, Virtualization, Programming Languages

Archive for January, 2010

这样也能算圆周率

without comments

reddit programming版面最近的热帖,下面这个程序输出的结果是一个近似的圆周率(3.156)。

#define _ F-->00 || F-OO--;
long F=00,OO=00;
main(){F_OO();printf("%1.3f\n", 4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
       _-_-_-_-_-_-_-_-_
            _-_-_-_
}

乍看下这个程序有点莫名其妙,分析一下宏后就知道它的方法了。两个全局变量F和OO分别记录 圆的面积和直径 的相反数,根据4*面积/直径/直径就能得到近似的圆周率了。

至于面积和直径的计算,F在会在每一个_展开的地方减一,这样就得到了圆的面积。直径的计算要展开几行代码才能看得更清楚:

F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;

F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;
-F-->00 || F-OO--;

这是用cpp展开圆形前两行代码的结果,因为或运算的特殊性,F- OO- -只会在每一段的第一行执行,所以OO- -执行的次数就等于圆的直径了。

Written by zellux

January 28th, 2010 at 11:22 am

Posted in Programming

Tagged with

强制程序使用int 0×80做系统调用

with 5 comments

因为大多数情况下程序都是通过libc间接地发出系统调用的,所以只要编译一个只使用int 0×80的glibc库,然后在执行程序的时候用LD_LIBRARY_PATH或其他方法指定使用新编译的glibc库即可。

以glibc-2.9, Linux i386为例,在sysdeps/unix/sysv/linux/i386/syscall.S中可以看到

 ENTRY (syscall)

     PUSHARGS_6      /* Save register contents.  */
     _DOARGS_6(44)       /* Load arguments.  */
     movl 20(%esp), %eax /* Load syscall number into %eax.  */
     ENTER_KERNEL        /* Do the system call.  */
     POPARGS_6       /* Restore register contents.  */
     cmpl $-4095, %eax   /* Check %eax for error.  */
     jae SYSCALL_ERROR_LABEL /* Jump to error handler if error.  */

这里使用了ENTER_KERNEL这个宏做系统调用,接下来在sysdeps/unix/sysv/linux/i386/sysdep.h里可以找到这个宏的定义

/* The original calling convention for system calls on Linux/i386 is
   to use int $0x80.  */
#ifdef I386_USE_SYSENTER
# ifdef SHARED
#  define ENTER_KERNEL call *%gs:SYSINFO_OFFSET
# else
#  define ENTER_KERNEL call *_dl_sysinfo
# endif
#else
# define ENTER_KERNEL int $0x80
#endif

而I386_USE_SYSENTER这个宏也是在同一个头文件中定义的

#if defined USE_DL_SYSINFO \
    && (!defined NOT_IN_libc || defined IS_IN_libpthread)
# define I386_USE_SYSENTER   1
#else
# undef I386_USE_SYSENTER
#endif

把这个条件宏改成

#undef I386_USE_SYSENTER

就能强制glibc使用int 0×80了。

这个方法只能过滤通过glibc做的系统调用。对于程序里写死使用sysenter的情况就要使用反汇编或者其他手段了。

Written by zellux

January 26th, 2010 at 10:56 am

Posted in Programming

Tagged with ,

Git命令行自动补全

without comments

Pro Git上看到的技巧,git的源代码包里的contrib/completion目录下有个git-completion.bash,把这个文件保存到~/.git-completion.bash,然后在.bashrc中加入一行

source ~/.git-completion.bash

这样就能在bash下用tab自动补全git命令、branch等内容了。另外Debian/Ubuntu里有个包就叫git-completion,这个包安装完成后会自动把这个补全脚本放到/etc/bash_completion.d/下,由bash-compleletion载入执行。

Written by zellux

January 25th, 2010 at 3:45 pm

Posted in Tools

Tagged with

使用grep查找进程的技巧

without comments

使用grep在ps aux的输出结果中查找进程的时候经常会把grep进程本身也找出来,比如查找emacs进程:

$ ps aux | grep emacs
wyx   7090  0.0  0.0   3336   796 pts/2 S+ 04:49 0:00 grep emacs
wyx  10128  0.1  4.9  66904 50388 pts/3 S+ Jan21 2:21 emacs

一个常见的防止grep进程出现的方法就是在后面再加一个grep -v grep:

$ ps aux | grep emacs | grep -v grep
wyx  10128  0.1  4.9  66904 50388 pts/3 S+ Jan21 2:21 emacs

今天在Santosa的博客上看到了另一个巧妙的做法,使用grep [e]macs来搜索emacs这个进程:

$ ps aux | grep [e]macs
wyx  10128  0.1  4.9  66904 50388 pts/3 S+ Jan21 2:21 emacs

为什么会有这样的效果,知道grep正则中[]的作用后想一想就能明白啦。很有意思的trick,虽然说它比grep -v grep也未必方便多少,因为后者能通过alias简化输入。

Written by zellux

January 21st, 2010 at 8:47 pm

Posted in Tools

Tagged with ,

FireStats icon Powered by FireStatsBetter Tag Cloud