individuality 一研为定
算法 内核 编译原理 设计模式
#include
void show_memory_01(void* start, int memory_len)
{
int i;
char* p = (char*)start;
for (i = 0; i < memory_len; i++)
{
if (i % 4 == 0) //输出地址
{
printf("0x%p ", p + i);
}
printf("%x", (p[i] & 0x000000f0) >> 4); //输出内存的数据
printf("%x ", p[i] & 0x0000000f);
if ((i + 1) % 4 == 0)
{
printf("\n");
}
}
}
void show_memory(void* start, int memory_len)
{
int i;
char* p = (char*)start;
for (i = 0; i < memory_len; i++)
{
printf("%x ", p[i]);
if ((i + 1) % 4 == 0)
{
printf("\n");
}
}
}
int main() {
float f = 1.456;
int arr[3] = {
1,2,3 };
show_memory(&f, sizeof(f));
printf("\n");
show_memory(arr, sizeof(arr));
return 0;
}
参考链接
注意: 计算机内存中存储的是补码
ff ff ff fa
代表负数,所以先转化为原码,然后转为10进制,就是把ff ff ff fa
除了符号位各位取反加一得到原码1000 0000 0000 0000 0000 0000 0000 0110
也就是-6
求补码快捷方法:从高位开始按位去反,直到最后一个1(并且最后一个1保持不变)
#include
void show_memory(void* start, int memory_len)
{
int i;
char* p = (char*)start;
for (i = 0; i < memory_len; i++)
{
if(i%4==0) //输出地址
{
printf("0x%p ", p+i);
}
printf("%x", (p[i]& 0x000000f0)>>4); //输出内存的数据
printf("%x ", p[i]& 0x0000000f);
if ((i + 1) % 4 == 0)
{
printf("\n");
}
}
}
int main()
{
int i = 5, j = 7;
printf("i & j=%d\n", i & j);
printf("i | j=%d\n", i | j);
printf("i ^ j=%d\n", i ^ j);
printf("~i=%d\n", ~i);
//位运算实战
float f = 1.456;
show_memory(&f, sizeof(f));
int arr[3] = {
1,2,3 };
show_memory(arr, sizeof(arr));
//异或交换两个数
i = i ^ j;
j = i ^ j;
i = i ^ j;
printf("i=%d,j=%d\n", i, j);
//找出一个整数最低位为1的那个数
printf("最低位为1的值 %d\n", 12 & -12);
return 0;
}
1.有两个变量a与b,在不使用第三个量的情况下,通过异或操作来交换这两个变量的值,这种交换相对于之前的加法交换有何优势?
i = i^ j ;
j = j ^i ;
i = i ^j ;
0000 0101 => 5
1111 1011 => -5
混合运算规则:不同数据类型转换级别
注意事项:
#include
#include
void big_int_mul()
{
long long l;
l = (long long)131072 * 131072;
printf("%lld\n", l);
}
int main()
{
char b = 0x93 << 1 >> 1;
printf("%x\n", b);
b = 0x93 << 1; //赋值一瞬间发生了丢失
b = b >> 1;
printf("%x\n", b);
big_int_mul();
return 0;
}
整型运算按4个字节进行
0x93
0000 0000 0000 0000 0000 0000 1001 00110000 0000 0000 0000 0000 0001 0010 0110
b 0010 0110 0001 0011
void big_int_mul()
{
long long l;
l = (long long)131072 * 131072;
printf("%lld\n", l);
}
#include
#include
//浮点型常量默认按8字节运算
int main()
{
float f = 12345678900.0 + 1;
double d = f;
printf("%f\n", f); // 12345678848。000000
printf("%f\n", 12345678900.0 + 1); // 12345678901.000000
return 0;
}
#include
#include
void const_two()
{
char str[] = "hello world";
char str1[] = "how do you do";
char* const ptr = str;//和普通变量一致,代表ptr被修改
str[0] = 'H';
puts(ptr);
ptr[0] = 'n'; //合法
puts(ptr);
//ptr = "world"; //非法,编译错误,error C2166: 左值指定const对象
}
int main()
{
const int i = 5;//i在下面的代码中不能修改,是常量
char str[] = "hello world";
const char* ptr = str;//这里代表ptr指向的空间不能被修改
str[0] = 'H'; //操作合法
puts(ptr);
ptr = "world";
//ptr[0] = 'n'; //操作非法,编译错误,提示error C2166: 左值指定const对象
puts(ptr);
//const修饰指针的第二种情况
const_two();
return 0;
}
数据类型自身的对齐值如下:
架构:
1、英特尔:(AMD) x86 mov AL BL ; 是BL 放到 AL 中
2、龙芯 (Mips)
3、ARM 高通、苹果、华为
4、Powerpc IBM
不同架构间汇编指令差异很大
复杂指令集:变长 x86
精简指令集:等长 arm
1、C文件预处理后变为 i 文件
2、文件经过编译后变为s文件汇编文件
3、汇编文件经过汇编变为目标文件oj
4、Obj经过链接变为exe
常用指令
1、
表示任意寄存器,若其后带有数字,则指定其位数,如reg<32>表示32位 寄存器(eax、ebx、ecx、edx、esi、edi、esp或ebp);表示16位寄存器(ax,bx、cx或dx);表示8位寄存器(ah、al、bh、bl、ch、cl、dh、dl)
2、
:表示内存地址(如[eax]、[var+4]或 dword ptr[eax+ebx]).
3、
:表示8位、16位或32位常数。表示8位常数;
表示16位常数;
表示32位常数。
汇编语言学习启航
英特尔CPU 栈顶在低地址,栈底在高地址
(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。
(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。
DWORD PTR
是什么意思:dword
双字 就是四个字节ptr
pointer缩写 即指针[]
里的数据是一个地址值,这个地址指向一个双字型数据比如:mov eax, dword ptr [12345678] 把内存地址12345678中的双字型(32位)数据赋给eax
lea
指令的作用:是 DWORD PTR_arrs[ebp]
对应空间的内存地址值放到eax中(1)条件码(标志位)
除了整数寄存器,CPU还维护着一组条件码(标志位)寄存器,它们描述了最近的算术或逻辑运算操作的属性。可以检测这些寄存器来执行条件分支指令,最常用的条件码有:
常见的算术逻辑运算指令(add、sub、 imul, or、and、shl、inc、dec、not、sal等)会设置条件码。但有两类指令只设置条件码而不改变任何其他寄存器:cmp指令和sub指令的行为一样,test指令与and指令的行为一样,但它们只设置条件码,而不更新目的寄存器。
jcondition
条件转跳指令,就是根据条件码ZF和SF来实现转跳。#include
#include
int main()
{
int arr[3]={
1,2,3};
int *p;
int i=5;
int j=10;
i=arr[2];
p=arr;
printf("i=%d\n",i);
if (i < j)
{
printf("i is small\n");
}
system("pause");
}
主体汇编代如下
; COMDAT _main
_TEXT SEGMENT
_j$ = -56 ; size = 4
_i$ = -44 ; size = 4
_p$ = -32 ; size = 4
_arr$ = -20 ; size = 12
__$ArrayPad$ = -4 ; size = 4
_main PROC ; COMDAT
; 4 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81 ec fc 00 00
00 sub esp, 252 ; 000000fcH
00009 53 push ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd 04 ff ff
ff lea edi, DWORD PTR [ebp-252]
00012 b9 3f 00 00 00 mov ecx, 63 ; 0000003fH
00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
0001c f3 ab rep stosd
0001e a1 00 00 00 00 mov eax, DWORD PTR ___security_cookie
00023 33 c5 xor eax, ebp
00025 89 45 fc mov DWORD PTR __$ArrayPad$[ebp], eax
00028 b9 00 00 00 00 mov ecx, OFFSET __8B08B150_main@c
0002d e8 00 00 00 00 call @__CheckForDebuggerJustMyCode@4
;--------------------------------------
; 下面代码主要实现 数组为什么数组名为其首地址
;--------------------------------------
; 5 : int arr[3]={
1,2,3};
00032 c7 45 ec 01 00
00 00 mov DWORD PTR _arr$[ebp], 1
00039 c7 45 f0 02 00
00 00 mov DWORD PTR _arr$[ebp+4], 2
00040 c7 45 f4 03 00
00 00 mov DWORD PTR _arr$[ebp+8], 3
; 6 : int *p;
; 7 : int i=5;
00047 c7 45 d4 05 00
00 00 mov DWORD PTR _i$[ebp], 5
; 8 : int j=10;
0004e c7 45 c8 0a 00
00 00 mov DWORD PTR _j$[ebp], 10 ; 0000000aH
; 9 : i=arr[2];
00055 b8 04 00 00 00 mov eax, 4
0005a d1 e0 shl eax, 1
0005c 8b 4c 05 ec mov ecx, DWORD PTR _arr$[ebp+eax]
00060 89 4d d4 mov DWORD PTR _i$[ebp], ecx
; 10 : p=arr;
00063 8d 45 ec lea eax, DWORD PTR _arr$[ebp]
00066 89 45 e0 mov DWORD PTR _p$[ebp], eax
; 11 : printf("i=%d\n",i);
00069 8b 45 d4 mov eax, DWORD PTR _i$[ebp]
0006c 50 push eax
0006d 68 00 00 00 00 push OFFSET ??_C@_05BKKKKIID@i?$DN?$CFd?6@
00072 e8 00 00 00 00 call _printf
00077 83 c4 08 add esp, 8
; 12 : if (i < j)
0007a 8b 45 d4 mov eax, DWORD PTR _i$[ebp]
0007d 3b 45 c8 cmp eax, DWORD PTR _j$[ebp]
00080 7d 0d jge SHORT $LN2@main
; 13 : {
; 14 : printf("i is small\n");
00082 68 00 00 00 00 push OFFSET ??_C@_0M@KNINEIJI@i?5is?5small?6@
00087 e8 00 00 00 00 call _printf
0008c 83 c4 04 add esp, 4
$LN2@main:
; 15 : }
; 16 : system("pause");
0008f 8b f4 mov esi, esp
00091 68 00 00 00 00 push OFFSET ??_C@_05PDJBBECF@pause@
00096 ff 15 00 00 00
00 call DWORD PTR __imp__system
0009c 83 c4 04 add esp, 4
0009f 3b f4 cmp esi, esp
000a1 e8 00 00 00 00 call __RTC_CheckEsp
; 17 : }
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81 ec cc 00 00
00 sub esp, 204 ; 000000ccH
00009 53 push ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd 34 ff ff
ff lea edi, DWORD PTR [ebp-204]
00012 b9 33 00 00 00 mov ecx, 51 ; 00000033H
00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
0001c f3 ab rep stosd
; 5 : int c;
; 6 : c = *a;
0001e 8b 45 08 mov eax, DWORD PTR _a$[ebp]
00021 8b 08 mov ecx, DWORD PTR [eax]
00023 89 4d f8 mov DWORD PTR _c$[ebp], ecx
; 7 : *a = *b;
00026 8b 45 08 mov eax, DWORD PTR _a$[ebp]
00029 8b 4d 0c mov ecx, DWORD PTR _b$[ebp]
0002c 8b 11 mov edx, DWORD PTR [ecx]
0002e 89 10 mov DWORD PTR [eax], edx
; 8 : *b = c;
00030 8b 45 0c mov eax, DWORD PTR _b$[ebp]
00033 8b 4d f8 mov ecx, DWORD PTR _c$[ebp]
00036 89 08 mov DWORD PTR [eax], ecx
; 9 : }
00038 5f pop edi
00039 5e pop esi
0003a 5b pop ebx
0003b 8b e5 mov esp, ebp
0003d 5d pop ebp
0003e c3 ret 0
Tips:
指针的间接访问在汇编的体现
_TEXT SEGMENT
_ret$ = -32 ; size = 4
_b$ = -20 ; size = 4
_a$ = -8 ; size = 4
_main PROC ; COMDAT
; 12 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81 ec e4 00 00
00 sub esp, 228 ; 000000e4H
00009 53 push ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd 1c ff ff
ff lea edi, DWORD PTR [ebp-228]
00012 b9 39 00 00 00 mov ecx, 57 ; 00000039H
00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
0001c f3 ab rep stosd
; 13 : int a,b,ret;
; 14 : a =16;
0001e c7 45 f8 10 00
00 00 mov DWORD PTR _a$[ebp], 16 ; 00000010H
; 15 : b = 64;
00025 c7 45 ec 40 00
00 00 mov DWORD PTR _b$[ebp], 64 ; 00000040H
; 16 : ret = 0;
0002c c7 45 e0 00 00
00 00 mov DWORD PTR _ret$[ebp], 0
; 17 : swap(&a,&b);
00033 8d 45 ec lea eax, DWORD PTR _b$[ebp]
00036 50 push eax
00037 8d 4d f8 lea ecx, DWORD PTR _a$[ebp]
0003a 51 push ecx
0003b e8 00 00 00 00 call _swap
00040 83 c4 08 add esp, 8
; 18 : ret = a - b;
00043 8b 45 f8 mov eax, DWORD PTR _a$[ebp]
00046 2b 45 ec sub eax, DWORD PTR _b$[ebp]
00049 89 45 e0 mov DWORD PTR _ret$[ebp], eax
; 19 : printf("ret=%d\n",ret);
0004c 8b f4 mov esi, esp
0004e 8b 45 e0 mov eax, DWORD PTR _ret$[ebp]
00051 50 push eax
00052 68 00 00 00 00 push OFFSET ??_C@_07EGPJDCKD@ret?$DN?$CFd?6?$AA@
00057 ff 15 00 00 00
00 call DWORD PTR __imp__printf
0005d 83 c4 08 add esp, 8
00060 3b f4 cmp esi, esp
00062 e8 00 00 00 00 call __RTC_CheckEsp
; 20 : system("pause");
00067 8b f4 mov esi, esp
00069 68 00 00 00 00 push OFFSET ??_C@_05PDJBBECF@pause?$AA@
0006e ff 15 00 00 00
00 call DWORD PTR __imp__system
00074 83 c4 04 add esp, 4
00077 3b f4 cmp esi, esp
00079 e8 00 00 00 00 call __RTC_CheckEsp
; 21 : return ret;
0007e 8b 45 e0 mov eax, DWORD PTR _ret$[ebp]
; 22 : }
00081 52 push edx
00082 8b cd mov ecx, ebp
00084 50 push eax
00085 8d 15 00 00 00
00 lea edx, DWORD PTR $LN6@main
0008b e8 00 00 00 00 call @_RTC_CheckStackVars@8
00090 58 pop eax
00091 5a pop edx
00092 5f pop edi
00093 5e pop esi
00094 5b pop ebx
00095 81 c4 e4 00 00
00 add esp, 228 ; 000000e4H
0009b 3b ec cmp ebp, esp
0009d e8 00 00 00 00 call __RTC_CheckEsp
000a2 8b e5 mov esp, ebp
000a4 5d pop ebp
000a5 c3 ret 0
000a6 8b ff npad 2
$LN6@main:
000a8 02 00 00 00 DD 2
000ac 00 00 00 00 DD $LN5@main
$LN5@main:
000b0 f8 ff ff ff DD -8 ; fffffff8H
000b4 04 00 00 00 DD 4
000b8 00 00 00 00 DD $LN3@main
000bc ec ff ff ff DD -20 ; ffffffecH
000c0 04 00 00 00 DD 4
000c4 00 00 00 00 DD $LN4@main
$LN4@main:
000c8 62 DB 98 ; 00000062H
000c9 00 DB 0
$LN3@main:
000ca 61 DB 97 ; 00000061H
000cb 00 DB 0
_main ENDP
_TEXT ENDS
; Function compile flags: /Odtp /RTCsu /ZI
; File g:\code_2021\»ã±à½²½â\»ã±à½²½â2\main.c
; COMDAT _swap
_TEXT SEGMENT
_c$ = -8 ; size = 4
_a$ = 8 ; size = 4
_b$ = 12 ; size = 4
_swap PROC ; COMDAT
; 4 : {
00000 55 push ebp
00001 8b ec mov ebp, esp
00003 81 ec cc 00 00
00 sub esp, 204 ; 000000ccH
00009 53 push ebx
0000a 56 push esi
0000b 57 push edi
0000c 8d bd 34 ff ff
ff lea edi, DWORD PTR [ebp-204]
00012 b9 33 00 00 00 mov ecx, 51 ; 00000033H
00017 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
0001c f3 ab rep stosd
; 5 : int c;
; 6 : c = *a;
0001e 8b 45 08 mov eax, DWORD PTR _a$[ebp]
00021 8b 08 mov ecx, DWORD PTR [eax]
00023 89 4d f8 mov DWORD PTR _c$[ebp], ecx
; 7 : *a = *b;
00026 8b 45 08 mov eax, DWORD PTR _a$[ebp]
00029 8b 4d 0c mov ecx, DWORD PTR _b$[ebp]
0002c 8b 11 mov edx, DWORD PTR [ecx]
0002e 89 10 mov DWORD PTR [eax], edx
; 8 : *b = c;
00030 8b 45 0c mov eax, DWORD PTR _b$[ebp]
00033 8b 4d f8 mov ecx, DWORD PTR _c$[ebp]
00036 89 08 mov DWORD PTR [eax], ecx
; 9 : }
00038 5f pop edi
00039 5e pop esi
0003a 5b pop ebx
0003b 8b e5 mov esp, ebp
0003d 5d pop ebp
0003e c3 ret 0
_swap ENDP
_TEXT ENDS
END