随笔分类 - 程序员的自我修养
摘要:#include <stdio.h>#include <stdlib.h>intmain(){chara=1;charb=2;intc[10];inti;for(i=0;i<=10;i++)c[i] =i* (i<<8);printf("%d %d\n",a,b);return0;}运行结果是多少?答案是:0 0要知道为什么,首先要能够划出栈的布局,然后确切的理解小端机是什么意思,知道数组的增长方式,看下图:虽然自己对栈布局和大小端机都有了解,无奈在一对一纸上笔试的时候还是没有做对。回来在Centos下试了一下,在windows下是
阅读全文
摘要:一:列文件清单1. List(gdb) list line1,line2二:执行程序要想运行准备调试的程序,可使用run命令,在它后面可以跟随发给该程序的任何参数,包括标准输入和标准输出说明符(<和>)和外壳通配符(*、?、[、])在内。如果你使用不带参数的run命令,gdb就再次使用你给予前一条run命令的参数,这是很有用的。利用set args 命令就可以修改发送给程序的参数,而使用show args 命令就可以查看其缺省参数的列表。(gdb)set args –b –x(gdb) show argsbacktrace命令为堆栈提供向后跟踪功能。Backtrace 命令产生一张
阅读全文
摘要:接上一篇:使用 GNU 的 GDB调试器,内存布局和栈 —— 01原文地址:http://www.dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php符号表 一个符号就是一个变量或者一个函数。符号表如你所想:就是在可执行文件中的一个包含变量和函数的表。 正常情况下符号表只包含符号的地址,因为计算机不使用我们给变量或者函数起的名字。 为了让GDB对我们来说有用,有必要能够通过变量或者函数名来引用变量,而不是使用它们的地址。人类使用的是诸如“main()”或者“i”。 计算机使用如0x804b64d 或0xbffff784 之类的地址。因为
阅读全文
摘要:使用 GNU 的 GDB调试器,内存布局和栈原文地址:http://www.dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php我们会学些什么? 为了更高效的学习使用GDB,你必须了解帧,通常也成为栈帧,因为帧构成了栈。为了学习栈,我们需要了解可执行文件的内存布局。这里的讨论主要都是理论上的,但是为了使学习比较有趣,在本章结束之前我们将通过GDB来展现栈和栈帧的例子。 本章学习的东西似乎相当的理论化,但是对于达到以下目的来说却是非常有用的:1. 理解栈对于使用GDB调试器是绝对有必要的2. 了解一个进程的内存布局有助于我们理解什么是段错
阅读全文
摘要:#include<stdio.h>int main(){ int b = 3; int arr[] = {6,7,8,9,10}; int *ptr = arr; *(ptr++) += 123; //printf("%d,%d\n", *ptr, *(++ptr)); //输出:8,8 printf("%d,%d\n", *ptr, *(ptr++));//输出:8,7 return 0;}_cdecl 压栈方式是从右到左更加明显的例子:#include<stdio.h>int main(){ int a = 5, b = 7;
阅读全文
摘要:系统调用接口往往是通过中断来实现,比如Linux使用0x80号中断作为系统调用的入口,Windows采用0x2E号中断作为系统调用的入口。EAX名字C语言定义含义参数1exitvoid _exit(int status)退出进程EBX表示退出码2forkpid_t fork(void)复制进程EBX表示复制参数3readssize_t read( int fd,void *buf,size_t count)读文件EBX表示文件句柄,ECX表示读取缓冲地址,EDX表示读取的大小4writessize_t write( int fd,const void *buf,size_t count);写.
阅读全文
摘要:程序从main开始的吗?在执行main之前全局变量已经初始化,main函数的两个参数也被正确传了进来,堆和栈的初始化也已经完成,一些系统I/O也被初始化。完成上面这些工作的函数称为入口函数(Entry Point)。一个典型的运行步骤大致如下:·操作系统在创建进程后,把控制权交到了程序的入口,这个入口往往是运行库中的某个函数。·入口函数对运行库和程序运行环境进行初始化,包括堆、I/O、线程、全局变量构造等。·入口函数在完成初始化之后,调用main函数,正是开始执行程序主体部分·main函数执行完毕以后,返回到入口函数,入口函数进行清理工作,包括全局变量的
阅读全文
摘要:注:这一章的内容比较经典,之前看“深入理解计算机系统”的时候,也有看到栈帧(Stack Frame),但是不是很清楚,通过这一章的讲解,更清楚了。如果能再结合讲讲GDB调试的话就更完美了。栈:栈用于维护函数调用的上下文,离开了站函数调用就没法实现。堆:堆是用来容纳应用程序动态分配的内存区域,当程序使用malloc或new分配内存时,得到的内存来自堆里。Linux进程地址空间内存布局:在操作系统中,栈总是向下增长的。在i386下,栈顶由称为esp的寄存器进行定位。压栈的操作使栈顶的地址减小,弹出的操作使栈顶的地址增大。 程序栈实例在栈底的地址是0xbfffffff,而esp寄存器表明了栈顶,地址
阅读全文
摘要:第八章不是很感兴趣,直接跳到第九章。 DLL即动态链接库(Dynamic Link Library)的缩写. 一个DLL中有两个数据段,一个进程间共享,另一个私有. 当我们使用“__declspec(dllexport)”时表示该符号是从本DLL导出的符号。“__declspec(dllimport)”表示该符号是从别的DLL导入的符号。创建DLL:/*math.c*/__declspec(dllexport) double Add(double a, double b){return a+b;}__declspec(dllexport) double Sub(double a, doub..
阅读全文
摘要:静态链接浪费内存和磁盘空间、模块更新困难等问题,因此寻找一种更好的办法来组织程序模块。 静态链接对程序的更新、部署和发布也会带来很多麻烦。动态链接: 就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。动态链接的方式使得开发过程中各个模块更加独立、耦合度更小,便于不同的开发者和开发组织之间进行独立的开发和测试。动态链接还有一个特点就是程序在运行时可以动态的选择加载各种程序模块,使得插件成为可能。Linux系统中,ELF动态链接文件被称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象,它们一般都是以“.so”为扩展名;动态链接文件被称为动态..
阅读全文
摘要:由 user process角度来说明的话,VMA 是 user process 里一段 virtual address space 区域;virtual address space 是连续的内存空间,当然VMA 也会是连续的空间。VMA对 Linux 的主要好处是,可以内存的使用更有效率,並且更容易管理 user process address space。从另一个观念来看,VMA 可以让 Linux kernel 以 process 的角度来管理 virtual address space。Process 的 VMA对应,可以由 /proc/<pid>/maps 来查看;例如
阅读全文
摘要:进程与程序: 程序是一个静态的概念,它就是这些预编译好的指令和数据集合的一个文件;进程则是一个动态的概念,它是程序运行时的一个过程,很多时候把动态库叫做运行时也有一定的含义。 一般来来说,C语言指针大小的位数与虚拟空间的位数相同,如果32位平台下指针为32位,即4字节;64位平台下的指针为64位,即8字节。Intel自从1995年的Pentium Pro CPU开始采用了36位的物理地址,也就是可以访问高达64GB的物理内存。Intel把这个地址扩展方式叫做PAE(Physical Address Extension)。应用程序如何使用这些大于常规内存的空间?一个很常见的方法就是操作系统提供一
阅读全文
摘要:cl的位置:开始 –> 所有程序 -> Microsoft Visual Studio ->Visual Studio Tools -> Developer Command Prompt编译器产生通用对象文件格式 (COFF) 对象 (.obj) 文件。链接器产生可执行文件 (.exe) 或动态链接库文件 (DLL)。注意,所有编译器选项都区分大小写。若要编译但不链接,请使用/c。语法:CL [option...] file... [option | file]... [lib...] [@command-file] [/link link-opt...]选项optio
阅读全文
摘要:PE: Portable ExecutableCOFF: Common Object File Format跟ELF一样,PE中也允许程序员将变量后函数放到自定义段。在GCC中使用“__attribute__((section)("name"))”,在VISUAL C++中可以使用 “#pragma”编译器指示。#pragma data_seg("FOO")int global = 1;#pragma data_seg(".data")使用cl 编译器:开始 –> 所有程序 -> Microsoft Visual Stud
阅读全文
摘要:对于多个输入目标文件,链接器如何将它们的各个段合并到输出文件? 或者说,输出文件中的空间如何分配给输入文件?/*假设有a.c*/extern int sharedint main(){int a = 100;swap(&a,&shared);}/*b.c*/int shared = 1;void swap(int *a, int *b){*a ^= *b ^= *a ^= *b;}“链接器为目标文件分配地址和空间”中的“地址和空间”其实有两个含义:第一个是在输出的可执行文件中的空间;第二个是在装载后的虚拟地址中的虚拟地址空间。这个链接过程分两步:第一步 : 空间与地址分配扫描所
阅读全文
摘要:GAS中每个操作都是有一个字符的后缀,表明操作数的大小。C声明GAS后缀大小(字节)charb1shortw2(unsigned) int / long / char*l4floats4doublel8long doublet10/12注意:GAL使用后缀“l”同时表示4字节整数和8字节双精度浮点数,这不会产生歧义因为浮点数使用的是完全不同的指令和寄存器。操作数格式:格式操作数值名称样例(GAS = C语言)$ImmImm立即数寻址$1 = 1EaR[Ea]寄存器寻址%eax = eaxImmM[Imm]绝对寻址0x104 = *0x104(Ea)M[R[Ea]]间接寻址(%eax)= *ea
阅读全文
摘要:最近在看“程序员的自我修养”,看到了gcc内嵌汇编,静态链接那章的示例程序比较有趣,于是准备学习一下AT&T语法的gcc内嵌汇编。以前学微机原理的时候学习过汇编,现在基本上还给了老师,还是复习一下吧。像大家一样先来介绍一下AT&T语法与Intel asm语法的不同(顺便也学学基本知识):在 AT&T 汇编格式中,寄存器名要加上 '%' 作为前缀;而在 Intel 汇编格式中,寄存器名不需要加前缀。例如:AT&T 格式Intel 格式pushl %eaxpush eax在 AT&T 汇编格式中,用 '$' 前缀表示一个立即操
阅读全文
摘要:之前上嵌入式的课程,罗老师强调了函数可重入的重要性,而且还举例某某著名通信公司开发过程中函数不可重入导致的问题,于是对函数可不可重入比较注意,在看书的时候又遇到了这个问题,于是准备认真学习一下。一、可重入函数1)什么是可重入性?可重入(reentrant)函数可以由多于一个任务并发使用,而不必担心数据错误。相反,不可重入(non-reentrant)函数不能由超过一个任务所共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)。可重入函数可以在任意时刻被中断,稍后再继续运行,不会丢失数据。可重入函数要么使用本地变量,要么在使用全局变量时保护自己的数据。2)可重入函数:不为.
阅读全文
摘要:一、什么是条件变量与互斥锁不同,条件变量是用来等待而不是用来上锁的。条件变量用来自动阻塞一个线程,直到某特殊情况发生为止。通常条件变量和互斥锁同时使用。条件变量使我们可以睡眠等待某种条件出现。条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。条件的检测是在互斥锁的保护下进行的。如果一个条件为假,一个线程自动阻塞,并释放等待状态改变的互斥锁。如果另一个线程改变了条件,它发信号给关联的条件变量,唤醒一个或多个等待它的线程,重新获得互斥锁,重新评价条件
阅读全文
摘要:四种进程或线程同步互斥的控制方法1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。2、互斥量:为协调共同对一个共享资源的单独访问而设计的。3、信号量:为控制一个具有有限数量用户资源而设计。4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。临界区(Critical Section)临界区: 不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。每个进程中访问临界资源的那段代码称为临界区(Critical Section)(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。不论是硬件
阅读全文