秦悦明的运维笔记

linux下汇编语言编程

1. 一般套路

分两布,编译,linux下有两种常用的编译器,gnu的as和nasm,两者的区别是前者用AT&T语法,后者用了intel的语法,个人更喜欢gnu的语法一些。链接,链接分静态链接和动态链接两种。再加一个gdb调试器,基本上齐活了。

2. nasm例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
SECTION .data
EatMsg: db "Eat at Joe's",10
EatLen: equ $-EatMsg
SECTION .bss
SECTION .text
global _start
_start:
nop
mov eax,4
mov ebx,1
mov ecx,EatMsg
mov edx,EatLen
int 80H
mov eax,1
mov ebx,0
int 80H

直接抄<汇编语言基于linux环境>第五章的例子,调用了linux的systemcall ,也就是系统调用,eax是4,就是write系统调用。write的参数如下:

  • EAX contains the system call value.
  • EBX contains the file descriptor to write to.
  • ECX contains the start of the string.
  • EDX contains the length of the string.

ebx是文件句柄,1就是标准输出。
ecx是字符串的开始位置,这里是将EatMsg的地址传进去
edx是字符串的长度,这里也是用了equ的伪指令EatLen

全部传进去调用int 80H就调用传说中的的write系统调用了。
之后再调用退出系统调用,结束程序运行。ebx存储返回值,shell 里面可以用echo $?来查看。

1
2
编译:
nasm -f elf -g -F stabs eatsyscall.asm

-g 用于生成调试信息,-F 指定stabs格式,可以方便的用gdb调试。

之后是链接,用标准链接工具ld:

1
ld -o eatsyscall eatsyscall.o

运行就是一个标准输出:

1
2
[root@localhost ~]# ./eatsyscall
Eat at Joe's

3.as例子

跟nasm差不多:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#cpuid.s Sample program to extract the processor Vendor ID
.section .data
output:
.ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .text
.globl _start
_start:
movl $0, %eax
cpuid
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80

这里再抄一下<汇编语言程序设计>里面的例子,cpuid ,可以看到gas的语法明显和intel的不一样,最明显的差别是源操作数和目的操作数的位置是相反的。
这个调用了cpuid 的1号指令。将cpuid信息返回在ebx,ecx,edx三个寄存器中。

  • EBX contains the low 4 bytes of the string.
  • EDX contains the middle 4 bytes of the string.
  • ECX contains the last 4 bytes of the string.

movl将三个值分别送到output的指定位置,也就是’xxxxxxxxxxxx’中去。然后调用write系统调用来输出。最后是一个退出的系统调用。

1
2
3
4
5
6
7
8
编译:
[root@localhost ~]# as -gstabs -o cpuid.o cpuid.s
链接:
[root@localhost ~]# ld -o cpuid cpuid.o
运行:
[root@localhost ~]# ./cpuid
The processor Vendor ID is 'AuthenticAMD'
[root@localhost ~]#

4.section区域

一般linux程序需要定义三个区域,

  1. .data区域,定义已初始化变量
  2. .bss 定义为初始化变量
  3. .text 正文区域,里面要用.globl 指定开始点。

区域根据elf格式而来,不止这三个。linux下nasm和as都适用~

1
2
3
4
5
6
7
8
.section .data
< initialized data here>
.section .bss
< uninitialized data here>
.section .text
.globl _start
_start:
<instruction code goes here>

5.ia32下编程

上面提到的环境都能在ia32的模式下运行的很好,也就是说不用再切到dos下去调试。开个虚拟机就可以愉快的玩耍,很适合汇编的学习。实模式和保护模式一个最大的区别就是内存寻址是一个flat方式,可以直接引用内存。不用加段。

ensp安装

1.why

一个windows软件安装有啥好写的,因为这个软件有点反人类,各种bug,出错了以后一脸懵逼。完全没有cisco的模拟机简单好用。

2.版本

最好按照下面的版本来搞,操作系统我是win10的,win7的可能不需要这么安装我没试过。

软件 版本
ensp 1.2.00.500
virtualbox VirtualBox-5.1.26-117224-Win
wireshark ensp自带版本
WinPcap ensp自带版本
操作系统 win10 ,据说win7

关键是virtualbox的版本有点妖。有对应关系,我用下来,500版本的配5.1.26的使用没问题。
ensp的ar系列路由需要使用virtualbox的固定版本才能正常运行。

3.常见问题

1.路由器交换机不能多开,只能开一个,这个据说是win10跟ensp有些不兼容。官方出了个补丁,不过你得在论坛才能找到。 win10 1703系统无法启动多台设备解决方案

然后进行下面三步

  • 下载附件ensp_patch_500.rar,并解压;
  • 拷贝解压后的data和ensp_patch_500.exe文件至ensp安装目录\eNSP\vboxserver文件夹中
  • 双击ensp_patch_500.exe即可,重新打开ensp运行多台设备。

2.ar路由器无法启动
启动报40错误,这个是由于ar系列路由器的启动需要依赖virtualbox,而且对版本还有要求,试下来26版本的可用。

首先是BIOS开启虚拟化,amd系列的叫svm,不会的google搜一下。安装好了以后在ensp里面 菜单-工具-注册设备,勾选三个,三个都注册成功的话ok。

3.ar路由器启动报错41
这个应该是ar的虚拟化文件有问题,需要卸载ensp,然后删干净里面的vboxserver目录,重装即可。

4.如果还有问题

google搜索,ensp论坛搜索。

arp协议

1. 简介

地址解析协议(Address Resolution Protocol),其基本功能为透过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的顺利进行。它是IPv4中网络层必不可少的协议,不过在IPv6中已不再适用,并被邻居发现协议(NDP)所替代。

2. 格式

arp包格式

注意,arp包不是ip包,没有ip层。字段比较简单,看着就知道了。

3. arp request包:

arp request

arp requst是一个广播包,可以被交换机广播。

4.arp reply包:

arp reply

arp reply是一个单播包。

5. arp应用场景

在以太网协议中规定,同一局域网中的一台主机要和另一台主机进行直接通信,必须要知道目标主机的MAC地址。而在TCP/IP协议中,网络层和传输层只关心目标主机的IP地址。这就导致在以太网中使用IP协议时,数据链路层的以太网协议接到上层IP协议提供的数据中,只包含目的主机的IP地址。于是需要一种方法,根据目的主机的IP地址,获得其MAC地址。这就是ARP协议要做的事情。所谓地址解析(address resolution)就是主机在发送帧前将目标IP地址转换成目标MAC地址的过程。

6. arp proxy

arp代理,这个用的也不多,典型用法是https://www.cisco.com/c/en/us/support/docs/ip/dynamic-address-allocation-resolution/13718-5.html cisco 这个例子,路由器不能转发二层广播,所以host d 不会收到arp 请求,但是路由器知道host d的mac地址,而且默认开了arp proxy,所以路由器将自己接口的mac地址回复给了host a,这样a就能和d通信。

lvm日常操作

1.增加pv

操作相对简单

1
2
3
4
5
6
7
pvcreate /dev/sde
pvdisplay
vgextend volgroup0 /dev/sde
lvextend -l +100%FREE /dev/volgroup0/lveastmoney
resize2fs /dev/volgroup0/lveastmoney

操作均在线执行,不需要执行umount操作,扩起来很方便。

2. 缩减pv

首先要做的是umount操作,你得先卸载lv。他是个停机操作。所以得预估时间,基本上这种操作很少,加了以后不会再动了。

之后是resize2fs,

1
2
3
4
5
6
7
8
9
10
e2fsck -f /dev/volgroup0/lveastmoney
resize2fs /dev/volgroup0/lveastmoney 1000G
lvreduce -L 1000G /dev/volgroup0/lveastmoney
pvchange -xn /dev/sdd
#每秒输出一次进度:
pvmove -i 1 /dev/sdd
pvremove /dev/sdd

pvmove 很重要,将数据move出来。知道他100%free了,就可以pvmove了。

3. 应用场景

我觉得最适用的场景就是数据库类型的,或者说是存储型的服务器,原先有一块数据盘,后来感觉不够用了就增加一块,这里用lvm是特别好用的,不需要停机,对应用来说是无感知的。