UPDATE

现在在读博士,方向Computer architecture,具体而言GPGPUs architecture。个人主页 (http://zhaoxiahust.github.io/)。

Xwindows和一些编码

 

Xwindows--X server:
一个程序,它在某台机器上运行,接受远方clinet的请求,画出请求的图形。并把得到的响应发送给client,以便使得client知道下一步的动作,并把相应信息返还给server,以便更新图形。
 
本机telnet 启动服务器sun服务器,sun服务器的监听进程fork出telnet进程服务请求的机子.telnet进程fork出来两个,父进程负责与远方的机子通信,子进程exec成shell进程,解释执行父进程得到的命令,再将结果返回给远方的机子。
 
根据Xwindows原理,远方的机子应该是server,将收到的服务器的结果显示给用户看,Xwindows 的网络透明,本机telnet到多个远发的服务器,他们之间可以相互拷贝,使用鼠标选中一段字符,然后就可以在另外的程序里把该段字符粘贴过去,不论程序运行在什么地方。
 
窗口管理器:
窗口管理器是Gnome和KDE的一部分,主要功能:改变窗口大小,移动窗口,改变窗口的层叠顺序。
通常的x客户程序不需要知道有人想移动它,它只听窗口管理器的。你的窗口上的标题,按钮,全部都是窗口管理器提供的。关闭一个程序的窗口,是窗口管理器通知那个程序“有人要关掉你,你自己准备后事,然后退出吧”
 
系统的编码的问题在linux下经常遇到,例如windows下面的文件有时候名字和内容在linux下面是乱码,这主要是和linux的utf8编码与windows的gbk不同所导致的。在linux下面创建的文件默认是utf8,所以当用u盘拷贝到别人的windows机器时就变成了乱码。同理windows下面的问题拷贝到linux下面的问题,这可以通过mount 的时候增加转码的参数解决-o iocharset=utf8就ok了,这里的utf8是本地编码,可以通过locale命令实现

Latex xeCJK安装

最近在小某某的感召下用起了shell编程,进而拷来了texlive,中文支持的时候出了些小小的问题,现在分享下简单的解决方法。

先是利用安装盘里的texlive的包install.sh到本地硬盘,做得貌似就是复制i386的工作?

简单的英文文档支持没有问题,为了支持中文

 

cp -r /usr/local/texlive/2012/texmf-dist/tex/xelatex/xecjk  /usr/local/texlive/texmf-local/tex/xelatex/ 中,

注意root权限

 

利用texlive中的命令/usr/local/texlive/2012/bin/i386-linux/mktexlsr 更新包信息

 

简单的测试程序如下:

1.tex

 

\documentclass[12pt]{article}
\usepackage{xeCJK}
\setCJKmainfont{AR PL UKai CN}
\begin{document}
这是测试要显示的内容
\end{document}
 
利用xelatex命令
xelatex 2.tex 生成2.pdf

关于C语言的函数调用机制

今天在sina Weibo上看到一个人发的一道面试题目,有关于被调用函数中局部变量的若干问题。于是我回忆函数的调用机制,但是感觉有点模糊,以前在做MIT的JOS的时候碰到过,但是记忆有些模糊了,于是利用一个简单的程序进行了过程的重温。

OS是gentoo,GCC-4.5.3--gcc -S  *.c 进行反汇编

 

源代码如下

 

#include <stdio.h>

struct tree{
int a;
int b;
};//之所以定义结构体是想更深入的了解下
struct tree foo(int a, char b)
{
   struct tree m = {1,2};
   m.a = a;
   m.b = b;
   return m;
}

int main(void)
{
    int a = 2;
    char b = 3;
    struct tree m = {4,4}; 
    m = foo(a, b);
    a = m.a;
}
 
gcc反汇编后的代码:
	.file	"1.c"
	.text
.globl foo
	.type	foo, @function
foo:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$20, %esp
	movl	8(%ebp), %ecx
	movl	16(%ebp), %eax
	movb	%al, -20(%ebp)
	movl	$1, -8(%ebp)
	movl	$2, -4(%ebp)
	movl	12(%ebp), %eax
	movl	%eax, -8(%ebp)
	movsbl	-20(%ebp), %eax
	movl	%eax, -4(%ebp)
	movl	-8(%ebp), %eax
	movl	-4(%ebp), %edx
	movl	%eax, (%ecx)
	movl	%edx, 4(%ecx)
	movl	%ecx, %eax
	leave
	ret	$4
	.size	foo, .-foo
.globl main
	.type	main, @function
main:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$28, %esp
	movl	$2, -4(%ebp)
	movb	$3, -5(%ebp)
	movl	$4, -16(%ebp)
	movl	$4, -12(%ebp)
	movsbl	-5(%ebp), %edx
	leal	-16(%ebp), %eax
	movl	%edx, 8(%esp)
	movl	-4(%ebp), %edx
	movl	%edx, 4(%esp)
	movl	%eax, (%esp)
	call	foo
	subl	$4, %esp
	movl	-16(%ebp), %eax
	movl	%eax, -4(%ebp)
	leave
	ret
	.size	main, .-main
	.ident	"GCC: (Gentoo 4.5.3-r2 p1.5, pie-0.4.7) 4.5.3"
	.section	.note.GNU-stack,"",@progbits

 

 

其中指令比较有难度的就是

call 函数调用指令,在main函数中我们调用了foo函数,对应的汇编指令就是

call foo,操作系统做的工作就是sp=sp-4,然后将ip入栈,更换ip指向foo的指令

 

leave,将ebp的值赋给esp,然后pop出来ebp。注意pop 指令先读取出esp 对应栈单元的值,然后esp=esp+4;push指令先esp=esp-4,在将值存入esp所指的栈单元。

 

ret,函数返回指令,根据当前的esp读取出eip的值,然后返回主函数的指令

 

下面根据汇编代码和内存栈的变化说明程序的执行过程以及函数调用如何得到返回值

执行到调用call foo时内存栈的情况如下

注意leal    -16(%ebp), %eax ;将ebp-16的值赋给eax,通过记录结构体内存单元的地址实现返回值的使用。

 

call指令执行过后,执行到处理返回值之前,内存单元的情况如:

下面是函数是如何将返回值传递给主函数的

通过ebp,esp的变换,在调用函数中实现了返回值的传递。

 

下面执行到leave指令,复原esp,ebp,然后ret返回到main函数中。

上诉实验说明了很多东西以前貌似懂了,但是讲的话难度还是很大。反正赋闲在家,有心情的话还想把JOS重新做一边,顺便把很多书上的东西巩固一下。

KLEE小解

今天博士检查了我的PPT,各种不合格,需要努力的地方还有很多

现在针对PPT中没有给出的两个重要问题做下解释:

1.KLEE的工作流程

2 KLEE为什么是单线程的

 

1.KLEE的工作流程

我们从最普通的命令行说起

klee -libc=uclibc -posix-runtime *.bc

启动klee程序,读入参数

在LinkModule的时候,判断link哪个库,这里我们link的是uclibc和posix-runtime,注意link的先后顺序

然后初始化变量

进入runFuncitonAsMain进行运行

主要的环节在

while(state)//////判断sate是否全部终结

{

     从Executor中的一堆state中根据规则select出来一个state

      executeInstruction(state.instruciton, state);

     update(state)

}

在executeInstruction中根据不同的指令,执行不同的动作(相当于KLEE解释.bc文件)

 

如果遇到函数调用,则判断函数是外部函数还是内部函数,如果是外部函数,则调用外部库函数或者handler一下

如果是内部函数,则Frame入栈,state.pc更改,随着下一次state的选择执行调用函数的指令

当遇到返回指令的时候,如果state.stack为空,则solve 出constraint

若state.stack不为空,则相当于内部函数返回,pop Frame,更改state.pc

 

如果遇到分支指令,则根据condition,看是否必要在fork中生成新的falsestate,update(state)时添加新的状态

 

2KLEE的单线程

KLEE执行函数调用的方法是保留栈stack,popFrame和pushFrame

并没有为函数调用开启新的state或者其他特殊方法

当遇到pthread_create函数的时候,系统没有在uclibc和posix-runtime的库中链接到相应的函数于是直接调用了

系统函数pthread_create导致了KLEE的崩溃!!

VIM之cscope和taglist

一直想尝试下放弃sourceinsight,今天中午终于有时间试了下cscope和taglist插件

cscope主要是生成文档之间和函数之间的以来关系,比ctag要强大,taglsit主要是显示像sourceinsight一样的声明信息

 

cscope可以通过yum install安装

taglist主要是vim的插件,官网上可以下载,放到~/.vim/下(如果没有,则创建,记得打开vim的后,输入helptags  ~/.vim/doc/ ,这样才能查看 help文档)

 

在工程的根目录下面使用cscope的命令

find -name "*.h" -o -name "*.c" -o -name "*.cpp" > cscope.file

cscope -bkq -i cscope.file

ctags -R

分别查找到工程目录文件,添加到cscope.file中,然后根据它里面的内容,生成依赖关系

 

taglist的配置,可以写到/etc/vimrc 里面

let Tlist_Ctags_Cmd = '/usr/bin/ctags'

let Tlist_Show_One_File = 1

let Tlist_Exit_OnlyWindow = 1         仅标签页存在则关闭

 

 

在命令模式输入TlistOpen打开

ctrl+w可以在左右窗口切换

ctrl+t生成显示该定义的新的标签页,命令行模式输入tabn,tabp可切换

 

 

 

KLEE-之函数调用

关于函数的调用在klee使用中的体现

klee -libc=uclibc -posix-runtime *.bc

 

在executeInstrucion()中

通过判断instruction的类型,区分了call,和invoke

然后通过判断是不是直接的函数调用(是否为函数指针??)

如果是直接的函数调用,则调用函数executeCall(),如果是非直接,则做进一步处理,待考证

executeCall()

{

      if(f->isDeclaration())//////////如果函数仅仅有函数头, 即函数是外部函数,则调用

           callExternFunction();

          {

                       在这里面判断是否为定义的特殊函数例如klee_make_symbolic是,间接调用相应的函数

                       否,则使用系统调用相应的函数

         }

 

    else

    {

           函数的定义包含在module中,注意,这里的定义包含其实分为两种情况

          1.函数为自己定义的函数,这样刚开始的时候函数即在里面

          2.函数是外部函数,例如puts之类,但是因为我们使用klee的时候,加上了参数uclibc,和runPosixTime,所以在原module和

           库函数链接 的时候,就把定义链接了进去(经过实验,不知道为嘛printf没有被链接进去???)

 

          注意klee::main.cpp中链接的顺序,先是链接uclibc,将fopen之类的函数展开,在这里是展开为open

                                                                    然后链接PosixRuntime库,在runTime/Fd_32.c中有open的定义,调用了

                                                                     fd.c中的__fd_open函数,在这里面就判断了文件名参数path是否为symbolic

                                                                                           是,则使用klee定义的symbolic 模块

                                                                                           否,则调用真正的系统调用

   }

}

这样大概解释了pthread_create的调用过程

因为uclibc中的libc库没有pthread_create的定义,而且specialHanlder也没有,就直接进入了symtem调用最直接的 pthread_create

KLEE--constraint与state的关系

在 executor.cpp中,有run函数,一切程序的运行的驱动都是从这里开始的

line:2460

while (!states.empty() && !haltExecution) 

{

line2465:

 

    executeInstruction(state, ki);
.....................
....................
....................
   updateStates(&state);
}
 
executeInstruction顾名思义就是执行当前的Ki指令,当前选择的状态是state
updateState就是当这条指令执行结束的时候,更行状态集合
 
Executor::executeInstruction
{
让我们直接来看
line1452:Instruction:Br
      Executor::StatePair branches = fork(state, cond, false) //////////////cond是这个分支对应的条件
}
在Executor::fork()
{
line:712
   bool success = solver->evaluate(current, condition, res);//////////////////////通过这个,计算出当前情况下res的值,然后判断
 
 
 
line:807
  if (res==Solver::True)
 {
 }
 else if (res==Solver::False)
 {
  }
else
 {
            falseState = trueState->branch();       /////通过ExecutionState::branch(),复制了一份相同的falseState
            addedStates.insert(falseState);             ////////////////将falseState添加到addStates中,addedStates将在updateState中使用
 }
 
    addConstraint(*trueState, condition);///////////////////////////////ExecutionState::  state.addConstraint(condition);
   ///////////////////将condtion添加到  ConstraintManager constraints;里面去
 
    addConstraint(*falseState, Expr::createIsZero(condition));
 
}/////end of Executor::fork
 
我们看到在fork中,程序完成了state的复制和相应的condition的添加
 
 
 
现在让我们进入
Executor::updateStates()
{
line:2301
  states.insert(addedStates.begin(), addedStates.end());//完成了新加状态的添加
  /////////////////sates就是run中while循环终结的语句  while (!states.empty() && !haltExecution) 
}
 
 
 
Executor----------  std::set<ExecutionState*> states;
 
ExecutionState---------  ConstraintManager constraints;
 
 
在run中,Executor的states不断的更新,与之对应的是ExecutionState中的constraint也不断的更新
当系统遇到返回或者终结时,会根据入参state,solve出对应的constraint的解答
 
 
 
 

KLEE源码解析之klee_make_symbolic跟踪

使用klee时,一般要利用klee_make_symbolic函数,将要跟踪的变量标记为symbolic,但是klee是如何找到这个函数,并且对应标记的呢。。。。。

把klee_make_symbolic使用的分为两个过程,1。绑定 2.调用

 

1.绑定

在main.cpp中

 

line:1303
  Interpreter *interpreter = 
    theInterpreter = Interpreter::create(IOpts, handler);//////////调用static函数创建了interpretor
  handler->setInterpreter(interpreter);  ////////////设置了interpreter输出文件的路径??
 
line:1313
  const Module *finalModule = 
    interpreter->setModule(mainModule, Opts);.////////////////////////////在setModule函数中,完成了klee_make_symbolic函数到SpecialFunctionHandler::handleMakeSymbolic的绑定
 
 
 
Executor.cpp
跟踪Executor::setModule(Executor作为Interpreter的子类,实现了setModule虚函数)
 
line:348行
  specialFunctionHandler = new SpecialFunctionHandler(*this);/////实现了Executor::specialFuntionHandler变量与包含它的类变量的相互绑定
 
line:352
  specialFunctionHandler->bind();///////////////////////////////继续绑定过程
 
 
 
 
 
SpecialFunctionHandler.cpp
 
line:149   
Function *f = executor.kmodule->module->getFunction(hi.name);/////////利用llvm提供的功能函数,查找到对应的hi.name(这里为klee_make_symbolic)的Function指针
 
line:151
    if (f && (!hi.doNotOverride || f->isDeclaration()))//代码中存在klee_make_symbolic函数
      handlers[f] = std::make_pair(hi.handler, hi.hasReturnValue);///////////////////////  建立klee_make_symbolic函数返回指针和hi的对应关系,对应klee::SpecialFunctionHandler::handleMakeSymbolic() 
        
                      handlers_ty handlers;                                                      typedef std::map<const llvm::Function*, 
                                                                                                   std::pair<Handler,bool> > handlers_ty;
 
至此绑定结束
 
 
 
 
 
 
 
 
2.运行klee_make_symbolicd对应的handleMakeSymbolic函数
 
main.cpp
 
  if (!ReplayOutDir.empty() || !ReplayOutFile.empty())///////////感觉一直都为真吧???
 {
line1365
      interpreter->runFunctionAsMain(mainFn, out->numArgs, out->args, pEnvp);
 
 }

 

Executor.cpp

 

进入runFunctionAsMain函数

line3257

 

  run(*state);////////////  ExecutionState *state = new ExecutionState(kmodule->functionMap[f]);生成state,并完成一系列的初始工作
 
 
 
 
 
 
进入run函数
line2402
    while (!seedMap.empty())对应论文里面提到的state没有运行完,则程序继续运行
   {
line2415
      executeInstruction(state, ki);
   }
 
 
 
 
 
 
 
进入 executeInstruction(state, ki)函数
line1547
  case Instruction::Call: ///////指令作用为函数调用,顾名思义。。。
 {
line:1604
      executeCall(state, ki, f, arguments);
 
  }
 
 
 
 
 
 
 
 
 
进入 executeCall(state, ki, f, arguments);
函数头::
void Executor::executeCall(ExecutionState &state, 
                           KInstruction *ki,
                           Function *f,
                           std::vector< ref<Expr> > &arguments) {
 
line1125
      callExternalFunction(state, ki, f, arguments);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
进入callExternalFunction(state, ki, f, arguments);
函数头:
void Executor::callExternalFunction(ExecutionState &state,
                                    KInstruction *target,
                                    Function *function,
                                    std::vector< ref<Expr> > &arguments) {
 
 
line2665
  if (specialFunctionHandler->handle(state, function, target, arguments))/////注意这里的Executor::specialFunctionHandler为Executore::setModule生成的
 
  
 
 
 
 
 
 
 
 
 
进入SpecialFunctionHandler::handle函数
SpecialFuntionHandler.cpp
line161-163
  handlers_ty::iterator it = handlers.find(f);
  if (it != handlers.end()) {    
    Handler h = it->second.first;/////////////找到对应的Handler
 
 
line170
   (this->*h)(state, target, arguments);调用klee_make_symbolic对应的处理函数handleMakeSymbolic(ExecutionState &state,
                                                KInstruction *target,
                                                std::vector<ref<Expr> > &arguments) 成功
 
 
 
 
 
 
 
下面,让我们看一下handleMakeSymbolic函数是如何实现symbolic的添加
 
void SpecialFunctionHandler::handleMakeSymbolic(ExecutionState &state,
                                                KInstruction *target,
                                                std::vector<ref<Expr> > &arguments) {
追踪下参数的来源
 
 
 
handleMakeSymbolic第三个参数::
Executor.cpp
executeInstruction()函数
line1559中
    std::vector< ref<Expr> > arguments;
line1563中
 arguments.push_back(eval(ki, j+1, state).value);
这是handleMakeSymbolic第三个参数的来源
 
 
 
 
第二个参数
 
Executor.cpp
run()函数中
2412行
KInstruction *ki = state.pc;////////当前状态,当前指令的位置
 
 
第一个参数
state也是在run()函数中选择出来的////论文里是两种方式interleave!!!有待考察!!!
 
 
 
 
 
SpecialFuntionHandler.cpp
line:683行
    if (res) {
      executor.executeMakeSymbolic(*s, mo, name);
       }
 
 
跟踪进入executeMakeSymbolic
Executor.cpp
line:3103
    const Array *array = new Array(uniqueName, mo->size);
    bindObjectInState(state, mo, false, array);
    state.addSymbolic(mo, array);
完成了符号symbolic的添加
 
 
 
 
 

fedora16源设置

安装插件yum install yum-fastestmirror,他会自动寻找最快的源《或者直接下载163的源,fedora-163.repofedora-updates-163.repo, 放入/etc/yum.repos.d/,将其他的源备份为.save》。第三方源

su -c 'yum localinstall --nogpgcheck http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm

http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm'

,主要是安装闭源驱动。

之后就是yum更新,今天找到了传说中的axel,多线程下载,TNND,真的很快。方法如下:

先yum install axel,然后下载yum相关配置文件

cd /etc/yum/pluginconf.d/
axel http://cnfreesoft.googlecode.com/svn/trunk/axelget/axelget.conf
cd /usr/lib/yum-plugins/
axel http://cnfreesoft.googlecode.com/svn/trunk/axelget/axelget.py

这样用yum更新就是多线程下载了。

更新过程中可能会出现:

错误详细:[Errno 14] Could not open/read file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-15-i386

用yum update --nogpgcheck即可。

转自internet