Vim一些技巧
# 以十六进制形式查看,二进制代码文件
%!xxd # % 代表当前编辑的文件, xxd以十六进制显示该文件, xxd -r还原为二进制。
set nowrap # 不换行
w # 保存
wq # 保存退出
q! # 强制不保存退出
The ! qualifier tells Vim to force the operation.
For example
if the file was read-only you would use :w! to write it anyway.
If the file was modified and you wanted to quit without saving, you would use :q!.
:wq! just means force write and quit in one command.
# 在Vim中可以用添加前缀!的方式执行外部命令, 例如 !ls, 其结果将被在底部输出
!ls
!gcc % # % 表示当前文件
!./a.out
vim中:h是向左,l是向右,j是向下,k是向上
vs [filename] # 开启左右分屏
sp [filename] # 开启上下分屏
先按ctrl + w, 松开之后按w # 左右切换分屏
先按ctrl + w, 松开之后按h # 切换到左边的分屏
先按ctrl + w, 松开之后按l # 切换到右边的分屏
改变当前分屏的位置
先按ctrl+w,之后按r # 切换分屏位置
先按ctrl+w,之后shift+h # 将当前分屏移到最左边
先按ctrl+w,之后shift+l # 将当前分屏移到最右边
改变当前分屏的宽度
先按ctrl+w,之后输入数字N, 之后shift+> # 将当前分屏的宽度加N
先按ctrl+w,之后shift+> # 将当前分屏的宽度加一
先按ctrl+w,之后shift+< # 将当前分屏的宽度减一
Vim编辑器分屏操作
Vim 分屏操作
wc命令查看文件的行数,字数,字节数
print newline, word, and byte counts for each file
# 0行, 1个单词, 11个字节/字符(因为一个英文字符对应一个字节)
[root@localhost c]# ./helo_lin | wc
0 1 11
file命令查看文件信息
file a.out # 查看文件信息
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs),
for GNU/Linux 2.6.32, BuildID[sha1]=6e5966737b911cc5abc2cff490aa669416c1298f, not stripped
反汇编:将机器代码转换为汇编代码
# 把目标代码转为汇编代码
[root@localhost c]# objdump -d hello.o
hello.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: bf 00 00 00 00 mov $0x0,%edi
9: b8 00 00 00 00 mov $0x0,%eax
e: e8 00 00 00 00 callq 13 <main+0x13>
13: 5d pop %rbp
14: c3 retq
# 查看版本
-V
# 从二进制文件中反汇编那些特定指令机器码的section.
-d, --disassemble Display assembler contents of executable sections
# 与 -d 类似, 但反汇编所有section.
-D, --disassemble-all Display assembler contents of all sections
# 尽可能反汇编出源代码,尤其当编译的时候指定了-g这种调试参数时,效果比较明显。隐含了-d参数。
-S, --source Intermix source code with disassembly(既有源代码也有汇编)
# 显示档案库的成员信息,类似ls -l将lib*.a的信息列出。
-a
程序内存分区
一个程序本质上都是由 bss段、data段、text段三个组成的。
# bss段, data段 属于静态内存分配
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域
数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域
# text
代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域
# heap
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。
当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张)
当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。
# stack
栈又称堆栈,是用户存放程序临时创建的局部变量
也就是函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)
除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中
一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
text和data段都在可执行文件中(在嵌入式系统里一般是固化在镜像文件中),由系统从可执行文件中加载
而bss段不在可执行文件中,由系统初始化。
(深入理解计算机系统) bss段,data段、text段、堆(heap)和栈(stack)
objdump命令
#include实际上做的事情就是:把要引入的文件的内容插入到这里
#include<>只会从系统类库目录里查找头文件,在Linux下是
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include
/usr/local/include
/usr/include
找不到就会报错,所以引用系统头文件,使用<>
#include""查找位置是当前源文件所在目录
1、#include<>一般用于包含系统头文件,诸如stdlib.h、stdio.h、iostream等
2、#include""一般用于包含自定义头文件,比如我们自定义的test.h、declare.h等
include头文件时尖括号<>与双引号""的区别
GCC编译C语言代码的过程
gcc --verbose hello.c
# cc1 将.c源代码文件 编译成一个.s 汇编文件
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1 -quiet -v hello.c -quiet -dumpbase hello.c
-mtune=generic -march=x86-64 -auxbase hello -version -o /tmp/ccWC7Yvb.s
# as 将.s汇编文件 生成 .o目标文件
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
as -v --64 -o /tmp/ccQoZ2kO.o /tmp/ccWC7Yvb.s
# collect2 将.o文件和系统库的.o文件,库文件连接起来,生成可执行文件
# collect2是ld链接器的一个封装
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu
-m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtbegin.o
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64
-L/lib/../lib64 -L/usr/lib/../lib64
-L/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../..
/tmp/ccQoZ2kO.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s
--no-as-needed /usr/lib/gcc/x86_64-redhat-linux/4.8.5/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../lib64/crtn.o
# crt1.o、crti.o、crtbegin.o、crtend.o、crtn.o是gcc加入的系统标准启动文件,对于一般应用程序,这些启动是必需的
# -lc:链接libc库文件,其中libc库文件中就实现了printf等函数
collect2主要实现了两个额外的功能,都是为C++程序准备的。其一是生成代码调用全局静态对象的构造函数和析构函数;其二是支持Cfront方式生成模板代码。
collect2调用ld生成一个执行程序,然后调用nm程序,根据命名规则,查找所有的调用全局静态对象构造函数和析构函数的函数,并将这些函数保存为一张表,再生成一段代码遍历每个表项,调用对应的函数。所有这些信息被保存为一个C程序,然后编译、汇编为目标文件,在链接时作为第一个目标文件传给linker,做第二次链接。此功能实现在gcc/collect2.c文件内。通过在config.gcc文件里查找use_collect2=yes来确定哪些系统使用了该功能,PC上默认是关闭的。
gcc编译链接原理及使用
预处理功能:
(1)文件包含:把包含的.h文件找到并展开到#include所在处。
(2)条件编译:预处理器根据#if和#ifdef等编译命令及其后的条件,把源程序中的某些部分包含进来或排除在外,通常把排除在外的语句转换成空行。
(3)宏展开:预处理器将源程序中对宏的引用展开成相应的宏定义,只是纯粹的文本替换,没有任何计算。
#define MAX 10
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define area(x) ((x)*(x))
define的单行定义
#define A(x,y) x##y // A(123,456)结果是123456表示连接
#define B(x) #@x // 给x加上单引号
#define C(x) #x // 给x加双引号
define的多行定义
#define MACRO(arg1,arg2) do { \
test1; \
test2; \
}while(0)
// 在每一行的末尾要加上\,切记!
// 定义一个宏使用#define, 取消一个宏定义使用#undef
C语言宏#define(精通详解)
C语言宏嵌套的展开规则
C语言中define的全部使用方法总结
centos创建新用户
[root@localhost ~]# adduser hhx # 创建用户
[root@localhost ~]# passwd hhx # 为hhx用户设置密码