基于x86的Hello World汇编代码分析
汇编语言写HelloWorld
![汇编语言写HelloWorld](https://img.taocdn.com/s3/m/eb38f358a9114431b90d6c85ec3a87c240288a26.png)
汇编语言写HelloWorld在汇编语言中编写HelloWorld程序可以通过使用各种汇编指令来实现。
下面是一个示例程序,展示了如何使用x86汇编语言编写HelloWorld程序。
```assemblysection .datahello db 'Hello, World!',0section .textglobal _start_start:; 将HelloWorld字符串的地址存储在EBX寄存器中mov ebx, hello; 计算字符串长度,并将其存储在ECX寄存器中mov ecx, 13; 调用系统调用,打印字符串mov eax, 4mov edx, ecxint 0x80; 退出程序mov eax, 1xor ebx, ebxint 0x80```以上汇编代码使用NASM语法,可以用NASM汇编器进行汇编。
下面是使用Linux平台上的NASM和LD工具链进行编译和链接的命令:```bashnasm -f elf hello.asm -o hello.old -m elf_i386 hello.o -o hello./hello```在Windows平台上,可以使用MASM汇编器和ML链接器进行编译和链接。
下面是使用MASM和ML工具链进行编译和链接的命令:```bashmasm hello.asmlink hello.objhello.exe```运行以上程序后,将在控制台中输出"Hello, World!"。
这是一个简单的汇编语言编写的HelloWorld程序。
可以根据需要在汇编代码中进行修改和扩展,以实现更多功能。
汇编语言的灵活性和底层控制能力使其成为一种强大的编程工具。
【原译】汇编编程之:HelloWorld!详解
![【原译】汇编编程之:HelloWorld!详解](https://img.taocdn.com/s3/m/e000bc39f011f18583d049649b6648d7c1c70899.png)
【原译】汇编编程之:HelloWorld!详解免责申明(必读!):本博客提供的所有教程的翻译原稿均来⾃于互联⽹,仅供学习交流之⽤,切勿进⾏商业传播。
同时,转载时不要移除本申明。
如产⽣任何纠纷,均与本博客所有⼈、发表该翻译稿之⼈⽆任何关系。
谢谢合作!原⽂链接地址:第⼀次翻译,错误之处希望园友们不吝赐教。
如果你打算构建⾃⼰的操作系统(你马上就要做了,是吗?),你将需要熟悉汇编编程,⼀旦你了解了⼀个汇编语⾔,你也许甚⾄会,不论你如何选择,本教程将会介绍给你x86—64汇编语⾔,以后会推出"汇编编程"系列⽂章,会将⼀些更加⾼级的话题。
为了能够接收到本系列的⽂章,欢迎你通过rss或者是email订阅我的博客。
准备⼯作在我们开始之前,你需要个⼀台x86_64的linux机器,并且已经安装nasm程序,我想你可以下载并安装好nasm的。
如果你还没有linux机器,请。
"Hello World!"如⼤多数程序语⾔的开始教程⼀样,我们将会以⼀个最基础的hello world程序开始,我将通过展⽰代码,并且我建议你⼿⼯输⼊,不要直接复制粘贴,以便更好地记住它,⾸先,我们来创建⼀个⽬录存储我们的⼯作⽂件$ mkdir asm-tutorial$ cd asm-tutorial$ gedit hello-world.asm在上⾯的例⼦中,我⽤gedit打开了hello-world.asm,这个好⽤,通⽤的⽂本编辑器,不过,你如果更喜欢emacs,vim或其他的⽂本编辑器也随意。
好了,现在我们为我们的hello world程序输⼊代码,当你已经做完并且成功编译并且运⾏了以后我将会解释代码是如何⼯作的。
[bits 64]global _startsection .datamessage db "Hello, World!"section .text_start:mov rax, 1mov rdx, 13mov rsi, messagemov rdi, 1syscallmov rax, 60mov rdi, 0syscall创建可执⾏⽂件⼀旦你已经输⼊完了,保存⽂件,然后在终端输⼊下⾯的指令。
x86汇编指令集大全(带注释)
![x86汇编指令集大全(带注释)](https://img.taocdn.com/s3/m/dcc07ecbb8f3f90f76c66137ee06eff9aef8498f.png)
x86汇编指令集大全(带注释)X86和X87汇编指令大全(有注释)---------- 一、数据传输指令---------------------------------------------------- 它们在存贮器和寄存器、寄存器和输入输出端口之间传送数据. 1. 通用数据传送指令. MOV 传送字或字节. MOVSX 先符号扩展,再传送. MOVZX 先零扩展,再传送. PUSH 把字压入堆栈. POP 把字弹出堆栈. PUSHA 把AX,CX,DX,BX,SP,BP,SI,DI依次压入堆栈. POPA 把DI,SI,BP,SP,BX,DX,CX,AX依次弹出堆栈. PUSHAD 把EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI依次压入堆栈. POPAD 把EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX依次弹出堆栈. BSWAP 交换32位寄存器里字节的顺序XCHG 交换字或字节.(至少有一个操作数为寄存器,段寄存器不可作为操作数) CMPXCHG 比较并交换操作数.(第二个操作数必须为累加器AL/AX/EAX) XADD 先交换再累加.(结果在第一个操作数里) XLAT 字节查表转换.----BX指向一张256字节的表的起点,AL 为表的索引值(0-255,即0-FFH);返回AL为查表结果.([BX+AL]->AL) 2. 输入输出端口传送指令. IN I/O端口输入. ( 语法: IN 累加器, {端口号│DX} ) OUT I/O端口输出. ( 语法: OUT {端口号│DX},累加器 )输入输出端口由立即方式指定时, 其范围是 0-255; 由寄存器 DX 指定时,其范围是0-65535. 3. 目的地址传送指令. LEA 装入有效地址.例: LEA DX,string ;把偏移地址存到DX. LDS 传送目标指针,把指针内容装入DS.例: LDS SI,string ;把段地址:偏移地址存到DS:SI. LES 传送目标指针,把指针内容装入ES.例: LES DI,string ;把段地址:偏移地址存到ES:DI. LFS 传送目标指针,把指针内容装入FS.例: LFS DI,string ;把段地址:偏移地址存到FS:DI. LGS 传送目标指针,把指针内容装入GS.例: LGS DI,string ;把段地址:偏移地址存到GS:DI. LSS 传送目标指针,把指针内容装入SS.例: LSS DI,string ;把段地址:偏移地址存到SS:DI. 4. 标志传送指令. LAHF 标志寄存器传送,把标志装入AH. SAHF 标志寄存器传送,把AH 内容装入标志寄存器. PUSHF 标志入栈. POPF 标志出栈. PUSHD 32位标志入栈. POPD 32位标志出栈. ---------- 二、算术运算指令 ---------------------------------------------------- ADD 加法. ADC 带进位加法. INC 加 1. AAA 加法的ASCII码调整. DAA 加法的十进制调整. SUB 减法. SBB 带借位减法. DEC 减 1. NEG 求反(以 0 减之). CMP 比较.(两操作数作减法,仅修改标志位,不回送结果). AAS 减法的ASCII码调整. DAS 减法的十进制调整. MUL 无符号乘法.结果回送AH和AL(字节运算),或DX和AX(字运算), IMUL 整数乘法.结果回送AH和AL(字节运算),或DX和AX(字运算), AAM 乘法的ASCII码调整. DIV 无符号除法.结果回送:商回送AL,余数回送AH, (字节运算);或商回送AX,余数回送DX, (字运算). IDIV 整数除法.结果回送:商回送AL,余数回送AH, (字节运算);或商回送AX,余数回送DX, (字运算). AAD 除法的ASCII码调整. CBW 字节转换为字. (把AL中字节的符号扩展到AH中去) CWD 字转换为双字. (把AX中的字的符号扩展到DX中去) CWDE 字转换为双字. (把AX中的字符号扩展到EAX中去) CDQ 双字扩展. (把EAX中的字的符号扩展到EDX中去) ---------- 三、逻辑运算指令 ---------------------------------------------------- AND 与运算. OR 或运算. XOR 异或运算. NOT 取反. TEST 测试.(两操作数作与运算,仅修改标志位,不回送结果). SHL 逻辑左移. SAL 算术左移.(=SHL) SHR 逻辑右移. SAR 算术右移.(=SHR) ROL 循环左移. ROR 循环右移. RCL 通过进位的循环左移. RCR 通过进位的循环右移. 以上八种移位指令,其移位次数可达255次. 移位一次时, 可直接用操作码. 如SHL AX,1. 移位>1次时, 则由寄存器CL给出移位次数. 如MOV CL,04 SHL AX,CL ---------- 四、串指令---------------------------------------------------------- DS:SI 源串段寄存器 :源串变址. ES:DI 目标串段寄存器:目标串变址. CX 重复次数计数器. AL/AX 扫描值. D标志 0表示重复操作中SI和DI应自动增量; 1表示应自动减量. Z标志用来控制扫描或比较操作的结束. MOVS 串传送.( MOVSB 传送字符. MOVSW 传送字. MOVSD 传送双字. ) CMPS 串比较.( CMPSB 比较字符. CMPSW 比较字. ) SCAS 串扫描.把AL或AX的内容与目标串作比较,比较结果反映在标志位. LODS 装入串.把源串中的元素(字或字节)逐一装入AL或AX中.( LODSB 传送字符. LODSW 传送字. LODSD 传送双字. ) STOS 保存串.是LODS的逆过程. REP 当CX/ECX<>0时重复. REPE/REPZ 当ZF=1或比较结果相等,且CX/ECX<>0时重复. REPNE/REPNZ 当ZF=0或比较结果不相等,且CX/ECX<>0时重复. REPC 当CF=1且CX/ECX<>0时重复. REPNC 当CF=0且CX/ECX<>0时重复. ---------- 五、程序转移指令---------------------------------------------------- 1. 无条件转移指令 (长转移) JMP 无条件转移指令 CALL 过程调用 RET/RETF 过程返回.2. 条件转移指令(短转移,-128到+127的距离内)( 当且仅当(SF XOR OF)=1时,OP1<OP2 ) JA/JNBE 不小于或不等于时转移. JAE/JNB 大于或等于转移. JB/JNAE 小于转移. JBE/JNA 小于或等于转移. 以上四条,测试无符号整数运算的结果(标志C和Z). JG/JNLE 大于转移. JGE/JNL 大于或等于转移. JL/JNGE 小于转移. JLE/JNG 小于或等于转移. 以上四条,测试带符号整数运算的结果(标志S,O和Z). JE/JZ 等于转移. JNE/JNZ 不等于时转移. JC 有进位时转移. JNC 无进位时转移. JNO 不溢出时转移. JNP/JPO 奇偶性为奇数时转移. JNS 符号位为 "0" 时转移. JO 溢出转移. JP/JPE 奇偶性为偶数时转移. JS 符号位为 "1" 时转移.3. 循环控制指令(短转移) LOOP CX不为零时循环. LOOPE/LOOPZ CX 不为零且标志Z=1时循环. LOOPNE/LOOPNZ CX不为零且标志Z=0时循环. JCXZ CX为零时转移. JECXZ ECX为零时转移.4. 中断指令 INT 中断指令 INTO 溢出中断 IRET 中断返回5. 处理器控制指令 HLT 处理器暂停, 直到出现中断或复位信号才继续. WAIT 当芯片引线TEST为高电平时使CPU进入等待状态. ESC 转换到外处理器. LOCK 封锁总线. NOP 空操作. STC 置进位标志位. CLC 清进位标志位. CMC 进位标志取反. STD 置方向标志位. CLD 清方向标志位. STI 置中断允许位. CLI 清中断允许位. ---------- 六、伪指令 ---------------------------------------------------------- DW 定义字(2字节). PROC 定义过程. ENDP 过程结束. SEGMENT 定义段. ASSUME 建立段寄存器寻址. ENDS 段结束. END 程序结束. ---------- 七、处理机控制指令:标志处理指令 ------------------------------------ CLC 进位位置0指令 CMC 进位位求反指令 STC 进位位置为1指令 CLD 方向标志置1指令 STD 方向标志位置1指令 CLI 中断标志置0指令 STI 中断标志置1指令 NOP 无操作 HLT 停机 WAIT 等待 ESC 换码 LOCK 封锁 ========== 浮点运算指令集========================================= ============= ---------- 一、控制指令(带9B的控制指令前缀F变为FN时浮点不检查,机器码去掉9B)---- FINIT 初始化浮点部件机器码 9B DB E3 FCLEX 清除异常机器码 9B DB E2 FDISI 浮点检查禁止中断机器码 9B DB E1 FENI 浮点检查禁止中断二机器码 9B DB E0 WAIT 同步CPU和FPU 机器码 9B FWAIT 同步CPU和FPU 机器码 D9 D0 FNOP 无操作机器码 DA E9 FXCH 交换ST(0)和ST(1) 机器码 D9 C9 FXCH ST(i) 交换ST(0)和ST(i) 机器码 D9 C1iii FSTSW ax 状态字到ax 机器码 9B DF E0 FSTSW word ptr mem 状态字到mem 机器码 9B DD mm111mmm FLDCW word ptr mem mem到状态字机器码 D9 mm101mmm FSTCW word ptr mem 控制字到mem 机器码 9B D9 mm111mmm FLDENV word ptr mem mem到全环境机器码 D9 mm100mmm FSTENV word ptr mem 全环境到mem 机器码 9B D9 mm110mmm FRSTOR word ptr mem mem到FPU状态机器码 DD mm100mmm FSAVE word ptr mem FPU状态到mem 机器码 9B DD mm110mmm FFREE ST(i) 标志ST(i)未使用机器码 DD C0iii FDECSTP 减少栈指针1->0 2->1 机器码 D9 F6 FINCSTP 增加栈指针0->1 1->2 机器码 D9 F7 FSETPM 浮点设置保护机器码 DB E4 ---------- 二、数据传送指令 ---------------------------------------------------- FLDZ 将0.0装入ST(0) 机器码 D9 EE FLD1 将1.0装入ST(0) 机器码 D9 E8 FLDPI 将π装入ST(0) 机器码 D9 EB FLDL2T 将ln10/ln2装入ST(0) 机器码 D9 E9 FLDL2E 将1/ln2装入ST(0) 机器码 D9 EA FLDLG2 将ln2/ln10装入ST(0) 机器码 D9 EC FLDLN2 将ln2装入ST(0) 机器码 D9 ED FLD real4 ptr mem 装入mem的单精度浮点数机器码 D9 mm000mmm FLD real8 ptr mem 装入mem的双精度浮点数机器码 DD mm000mmm FLD real10 ptr mem 装入mem的十字节浮点数机器码 DB mm101mmm FILD word ptr mem 装入mem的二字节整数机器码 DF mm000mmm FILD dword ptrmem 装入mem的四字节整数机器码 DB mm000mmm FILD qword ptr mem 装入mem的八字节整数机器码DF mm101mmm FBLD tbyte ptr mem 装入mem的十字节BCD数机器码 DF mm100mmm FST real4 ptr mem 保存单精度浮点数到mem 机器码D9 mm010mmm FST real8 ptr mem 保存双精度浮点数到mem 机器码DD mm010mmm FIST word ptr mem 保存二字节整数到mem 机器码 DF mm010mmm FIST dword ptr mem 保存四字节整数到mem 机器码 DB mm010mmm FSTP real4 ptr mem 保存单精度浮点数到mem并出栈机器码 D9 mm011mmm FSTP real8 ptr mem 保存双精度浮点数到mem并出栈机器码 DD mm011mmm FSTP real10 ptr mem 保存十字节浮点数到mem并出栈机器码DB mm111mmm FISTP word ptr mem 保存二字节整数到mem并出栈机器码DF mm011mmm FISTP dword ptr mem 保存四字节整数到mem并出栈机器码 DB mm011mmm FISTP qword ptr mem 保存八字节整数到mem并出栈机器码 DF mm111mmm FBSTP tbyte ptr mem 保存十字节BCD数到mem并出栈机器码 DF mm110mmm FCMOVB ST(0),ST(i) <时传送机器码 DA C0iii FCMOVBE ST(0),ST(i) <=时传送机器码DA D0iii FCMOVE ST(0),ST(i) =时传送机器码DA C1iii FCMOVNB ST(0),ST(i) >=时传送机器码DB C0iii FCMOVNBE ST(0),ST(i) >时传送机器码 DB D0iii FCMOVNE ST(0),ST(i) !=时传送机器码 DB C1iii FCMOVNU ST(0),ST(i) 有序时传送机器码 DB D1iii FCMOVU ST(0),ST(i) 无序时传送机器码 DA D1iii ---------- 三、比较指令 -------------------------------------------------------- FCOM ST(0)-ST(1) 机器码 D8 D1 FCOMI ST(0),ST(i) ST(0)-ST(1) 机器码 DB F0iii FCOMIP ST(0),ST(i) ST(0)-ST(1)并出栈机器码 DF F0iii FCOM real4 ptr mem ST(0)-实数mem 机器码D8 mm010mmm FCOM real8 ptr mem ST(0)-实数mem 机器码 DC mm010mmm FICOM word ptr mem ST(0)-整数mem 机器码 DE mm010mmm FICOM dword ptr mem ST(0)-整数mem 机器码 DA mm010mmm FICOMP word ptr mem ST(0)-整数mem并出栈机器码DE mm011mmmFICOMP dword ptr mem ST(0)-整数mem并出栈机器码DA mm011mmm FTST ST(0)-0 机器码 D9 E4 FUCOM ST(i) ST(0)-ST(i) 机器码DD E0iii FUCOMP ST(i) ST(0)-ST(i)并出栈机器码DD E1iii FUCOMPP ST(0)-ST(1)并二次出栈机器码 DA E9 FXAM ST(0)规格类型机器码 D9 E5 ---------- 四、运算指令 -------------------------------------------------------- FADD 把目的操作数(直接接在指令后的变量或堆栈缓存器) 与来源操作数(接在目的操作数后的变量或堆栈缓存器) 相加,并将结果存入目的操作数 FADDP ST(i),ST 这个指令是使目的操作数加上 ST 缓存器,并弹出 ST 缓存器,而目的操作数必须是堆栈缓存器的其中之一,最后不管目的操作数为何,经弹出一次后,目的操作数会变成上一个堆栈缓存器了 FIADD FIADD 是把 ST 加上来源操作数,然后再存入 ST 缓存器,来源操作数必须是字组整数或短整数形态的变数FSUB 减FSUBP FSUBR 减数与被减数互换FSUBRP FISUB FISUBR FMUL 乘FMULP FIMUL FDIV 除FDIVP FDIVR FDIVRP FIDIV FIDIVR FCHS 改变 ST 的正负值 FABS 把 ST 之值取出,取其绝对值后再存回去。
x86汇编指令详解x86汇编指令详解
![x86汇编指令详解x86汇编指令详解](https://img.taocdn.com/s3/m/b671ff11eef9aef8941ea76e58fafab069dc440c.png)
x86汇编指令详解x86汇编指令详解指令包括三部分:数据传送指令、运算指令、跳转指令。
Intel寄存器包括:通用寄存器AX,BX,CX,DX;通用寄存器由分为8位、16位、32位,其中AL、AH是AX高、低8位寄存器,BL、BH是BX的高、低8位寄存器,CL、CH是CX的高、底8位寄存器,DL、DH是DX的高、低8位寄存器;段寄存器DS,ES,SS,CS,FS,GS;堆栈指针SP,程序计数器IP。
一、传送指令在存贮器和寄存器和输入输出端口之间传送数据。
1. 通用数据传送指令(R代表寄存器,M代表存储器,I代表立即数)MOV 第一操作数,第二操作数;功能:把第二操作数传给第一操作数,第一操作数必须是寄存器或存储单元,第二操作数可以是寄存器、存储器,也可以是立即数。
如:MOV AX,CX; CX——〉AXMOV BX,WORD;WORD——〉BXMOV AX, 10H;10H——〉AX第一操作数可以换成存储器,如word。
各种传送指令源操作数是寄存器MOV CH, ALMOV BP, SPMOV ECX, EBXMOV DS, AXMOV [BX], CH源操作数是存储单元MOV AL, [100H]MOV BX, ES:[DI]MOV EDX, [BX]MOV BX, VARW其中:VARW是字类型内存变量(下同)。
源操作数是立即数MOV AL, 89HMOV BX, -100HMOV EDX, 12345678HMOV VARW, 200HMOV [BX], 2345HPUSH 操作数;把操作数压入堆栈,堆栈指针SP+1;POP 操作数;把堆栈指针SP指定内容弹出到操作数指定位置。
如:PUSH AX;把AX内容送入堆栈POP AX;把堆栈内容弹出堆栈PUSHF 标志进栈格式为:PUSHF执行的操作:(SP)<-(SP)-2((SP)+1,(SP))<-(PSW)POPF 标志出栈格式为: POPF执行的操作:(PWS)<-((SP)+1,(SP))(SP)<-(SP+2)2. 输入输出端口传送指令IN AL,port;在IBM-PC机里,外部设备最多可有65536个I/O端口,端口(即外设的端口地址)为0000~FFFFH。
各种语言的HelloWorld编程
![各种语言的HelloWorld编程](https://img.taocdn.com/s3/m/3f35c06a65ce05087732132f.png)
各种语言的HelloWorld编程hello world百科名片C和C++“hello world”程序hello world作为所有编程语言的起始阶段,占据着无法改变的地位,所有中/英/法/德/美……版本的编程教材中,hello world总是作为第一个TEST记录于书本之中,所有的编程第一步就在于此了!经典之中的经典!hello world!目录简介 AKA 控制台: 传统图形界面应用开发工具: 基于web图形用户界面: 展开编辑本段简介这个例程是从Kernighan & Ritchie 合著的《The C Programme Language》开始有的,因为它的简洁,实用,并包含了一个程序所应具有的一切,因此为后来的些类书的作者提供了范例,一直待续到今。
我们刚开始接触计算机语言大多从Hello world 开始,下面是各种语言的Helloworld program:as400的RPGLE语言: D Vc_Hello s 100AC Eval Vc_Hello = 'Hello World!' C DSPLY Vc_Hello编辑本段AKA 控制台:ABC语言的Hello World程序WHILE (1=1) : WRITE \Ada语言的Hello World程序with Ada.Text_Io; use Ada.Text_Io; procedure Hello is beginPut_Line (\ end Hello;AmigaE语言的Hello World程序PROC main()WriteF('Hello, World!') ENDPROCAPL语言的Hello World程序'Hello World'Assembly语言的Hello World程序Accumulator-only architecture: DEC PDP-8, PAL-III assembler See the Example section of the PDP-8 article.Accumulator + index register machine: MOS 6502, CBM, ca65 asmMSG: .ASCIIZ \ LDX #0LDA MSG,X ; load initial char@LP: JSR $FFD2 ; CHROUT CBM KERNAL INXLDA MSG,X BNE @LP RTSAccumulator/Index microcoded machine: Data General Nova, RDOS See the example section of the Nova article.Expanded accumulator machine: Intel x86, MS-DOS, TASM MODEL SMALL IDEAL STACK 100HDATASEG语言的Hello World程序MSG DB 'Hello, world!$'CODESEG语言的Hello World程序MOV AX, @data MOV DS, AXMOV DX, OFFSET MSGMOV AH, 09H ; DOS: output ASCII$ string INT 21HMOV AX, 4C00H INT 21H ENDGeneral-purpose-register CISC: DEC PDP-11, RT-11, MACRO-11 .MCALL .REGDEF,.TTYOUT,.EXIT .REGDEFHELLO: MOV #MSG,R1 MOVB (R1),R0 LOOP: .TTYOUT MOVB +(R1),R0 BNE LOOP .EXITMSG: .ASCIZ /HELLO, WORLD!/ .END HELLOCISC: VAX, VMS, MACRO32 .title helloterm_name: .ascid /SYS$INPUT/ term_chan: .blkw 1 out_iosb: .blkq 1msg: .asciz /Hello, world!/ .entry start,0; establish a channel for terminal I/O $assign_s devnam=term_name,- chan=term_chan blbc r0,error; queue the I/O request $qio_s chan=term_chan,- func=#io$_writevblk,- iosb=out_iosb,- p1=msg,- p2=#13blbc r0,error $exit_s ; normal exit error: halt ; errorcondition .end startAWK语言的Hello World程序BEGIN { print \BASIC语言的Hello World程序PRINT \MS BASIC语言的Hello World程序(traditional, unstructured) 10 PRINT \ 20 ENDTI-BASIC语言的Hello World程序isp \Structured BASIC语言的Hello World程序print \BCPL语言的Hello World程序GET \ LET START () BE $(WRITES (\ $)BF语言的Hello World程序++++++++++[>+++++++>++++++++++>+++>+<<<++.>+.+++++++..+++.>++.<.+++.------.--------.>+.>.C语言的Hello World程序#include int main(void) {printf(\ }C++语言的Hello World程序#include using namespace std; int main() {cout << \ return 0; }C#语言的Hello World程序class HelloWorldApp {public static void Main() {System.Console.WriteLine(\ } }Clean语言的Hello World程序module hello Start :: String Start = \CLIST语言的Hello World程序PROC 0WRITE Hello, World!COBOL语言的Hello World程序IDENTIFICATION DIVISION. PROGRAM-ID. HELLO-WORLD. ENVIRONMENT DIVISION. DATA DIVISION. PROCEDURE DIVISION. DISPLAY \ STOP RUN.Common Lisp语言的Hello World程序(format t \感谢您的阅读,祝您生活愉快。
androidARM汇编学习——helloworld
![androidARM汇编学习——helloworld](https://img.taocdn.com/s3/m/369bc3c87e192279168884868762caaedd33bac3.png)
androidARM汇编学习——helloworldadb putty 连上⼿机,⽤busybox vi 写⼀个 helloworld croot@HM2014813:/data/local/tmp # busybox vi hello.c#include <stdio.h>int main(int argc, char* argv[]){ printf("Hello ARM World\n"); return 0;}⽤ gcc 编译成汇编,并查看root@HM2014813:/data/local/tmp # gcc hello.c -S && cat ./hello.s.arch armv5te.fpu softvfp.eabi_attribute 20, 1.eabi_attribute 21, 1.eabi_attribute 23, 3.eabi_attribute 24, 1.eabi_attribute 25, 1.eabi_attribute 26, 2.eabi_attribute 30, 6.eabi_attribute 34, 0.eabi_attribute 18, 4.file "hello.c".section .rodata.align 2.LC0:.ascii "Hello ARM World\000".text.align 2.global main.type main, %functionmain:@ args = 0, pretend = 0, frame = 8@ frame_needed = 1, uses_anonymous_args = 0stmfd sp!, {fp, lr}add fp, sp, #4sub sp, sp, #8str r0, [fp, #-8]str r1, [fp, #-12]ldr r3, .L3.LPIC0:add r3, pc, r3mov r0, r3bl puts(PLT)mov r3, #0mov r0, r3sub sp, fp, #4@ sp neededldmfd sp!, {fp, pc}.L4:.align 2.L3:.word .LC0-(.LPIC0+8).size main, .-main.ident "GCC: (GNU) 4.8.2".section .note.GNU-stack,"",%progbits下⾯开始分析:.arch armv5te.fpu softvfp.eabi_attribute 20, 1.eabi_attribute 21, 1.eabi_attribute 23, 3.eabi_attribute 24, 1.eabi_attribute 25, 1.eabi_attribute 26, 2.eabi_attribute 30, 6.eabi_attribute 34, 0.eabi_attribute 18, 4.file "hello.c"开始这⼏⾏是给 ARM cpu 的声明,.arch 指明体系架构类型, .fpu 指明 Floating Point Unit 浮点运算单元的运算模式,接下去⼏⾏是 EABI 的 option, 最后⼀⾏指明⽂件名称.section .rodata.align 2.LC0:.ascii "Hello ARM World\000"c code ⾥的字符串 "Hello ARM World\n" 编译后存⼊ .rodata section 。
用汇编语言输出HelloWorld!
![用汇编语言输出HelloWorld!](https://img.taocdn.com/s3/m/681507eff605cc1755270722192e453610665b85.png)
⽤汇编语⾔输出HelloWorld!众所周知,⾸先从输出“Hello World!”开始学习⼀门编程语⾔已经是惯例了,汇编语⾔也不例外,下⾯我们将从输出“Hello World!”开始学习汇编语⾔。
⼀、编写源程序⾸先我们尝试⽤C语⾔来实现该功能:#include <stdio.h>int main() {printf("Hello World!"); // 输出“Hello World!”return 0;}可以看到,仅仅⽤了⼀⾏代码就实现了该功能。
那么⽤汇编语⾔⼜该如何去实现呢?data segment ;数据段string db 'Hello,World!$'data endscode segment ;代码段assume cs:code,ds:datastart:mov ax,data ;获取段基址mov ds,ax ;将段基址送⼊寄存器mov dx,offset stringmov ah,9int 21hmov ah,4chint 21hcode endsend start下⾯对该汇编程序的部分代码进⾏说明:string db 'Hello,World!$'定义⼀个名为string的字符串,string是字符串的名称,db是定义字节说明,字符串内容需⽤单引号括起,其中 $ 是串的结束标志assume cs:code,ds:data这是⼀条汇编伪指令,含义是指定code段与CS寄存器关联,data段与DS寄存器关联mov dx,offset string获取string的偏移地址mov ah,9int 21h调⽤9号DOS功能(显⽰字符串)mov ah,4chint 21h调⽤程序结束功能对⽐两段代码,显然同样的功能⽤汇编语⾔实现起来⽐⽤C语⾔实现起来更加复杂。
这是因为汇编语⾔是低级编程语⾔,⽽C语⾔等是⾼级编程语⾔,汇编语⾔更加接近底层。
汇编语言输出HelloWorld
![汇编语言输出HelloWorld](https://img.taocdn.com/s3/m/e2bcf1aab9f67c1cfad6195f312b3169a451eacb.png)
汇编语言输出HelloWorld```汇编语言输出HelloWorld```在计算机编程领域,汇编语言被广泛用于编写底层代码,实现对硬件的直接控制。
汇编语言具有高效性和灵活性等特点,因此在一些对性能要求较高的场景中得到了广泛应用。
本文将介绍如何使用汇编语言输出经典的HelloWorld字符串。
首先,我们需要了解汇编语言的基本语法和指令集。
x86汇编语言是一种常用的汇编语言,广泛应用于PC平台。
在x86汇编语言中,程序员通过编写一系列指令来控制计算机的运行。
这些指令可以操作和传输数据,进行逻辑判断和循环等操作。
通常,我们使用汇编语言编写的程序需要经过两个步骤才能在计算机上运行:汇编和链接。
汇编是将汇编代码翻译成机器码的过程。
在这个过程中,我们需要使用到一个叫做汇编器的工具。
不同的汇编器有不同的命令和语法,但是它们的基本原理都是相同的。
链接是将多个目标文件组合在一起,生成可执行文件的过程。
在这个过程中,我们需要使用一个叫做链接器的工具。
链接器会根据目标文件中的符号和地址信息,将各个目标文件合并成一个完整的程序。
接下来,我们来编写一个用汇编语言输出HelloWorld的示例程序:```assemblysection .datahello db 'Hello, World!',10len equ $-hellosection .textglobal _start_start:; 输出HelloWorld字符串mov eax, 4mov ebx, 1mov ecx, hellomov edx, lenint 0x80; 退出程序mov eax, 1xor ebx, ebxint 0x80```上面的程序使用到了x86汇编语言的一些基本指令,以及Linux系统调用来实现输出字符串和退出程序的功能。
其中,`.data`部分定义了程序中使用的数据段。
在这里,我们定义了一个以`hello`为标识的字符串,内容为`Hello, World!`,并以换行符结束。
x86汇编语言编写第一个汇编程序helloworld
![x86汇编语言编写第一个汇编程序helloworld](https://img.taocdn.com/s3/m/6f81f11c53d380eb6294dd88d0d233d4b14e3fab.png)
x86汇编语⾔编写第⼀个汇编程序helloworld ⽬录⼀、准备运⾏环境先准备汇编语⾔运⾏环境,在此下载:打开DOSBox0.74-win32-installer,安装。
⼆、编写汇编代码在汇编语⾔中,⽤分号;表⽰注释,类似于C/C++的//表⽰注释。
⼀个汇编程序的固定语法格式:;数据段data segment;此处定义数据变量类型data ends;代码段code segmentassume cs:code,ds:datastart:mov ax,datamov ds,ax;------;此处写需要实现的功能;------mov ah,4ch ;4ch表⽰从⽤户程序返回操作系统,结束程序int 21hcode endsend start输出"hello world"的代码:;数据段data segment;定义字节⼤⼩(8位)的字符串,变量名为string;db表⽰字节;0dh,0ah表⽰回车换⾏;$表⽰字符串终⽌符string db 'Hello World!',0dh,0ah,'$'data ends;代码段code segmentassume cs:code,ds:datastart:;push ds;mov ax,0;push axmov ax,datamov ds,ax;------lea dx,stringmov ah,09h ;ah是ax的⾼8位,功能号09h表⽰输出dx指向的字符串stringint 21h ;中断指令,调⽤⽤户程序,执⾏ah中设置的09h号功能;------mov ah,4ch ;功能号4ch表⽰从⽤户程序返回操作系统,结束程序int 21hcode endsend start本地可以⽤notepad++,将语⾔设置为A-Assembly,⽀持汇编语⾔的语法⾼亮,看着会⽐较舒服。
notepad++⽂本编辑器显⽰的语法⾼亮很好看:三、⽣成汇编程序并执⾏将第⼀步中下载的masm5⽂件夹存于D盘,⽐如路径为D:\masm5,然后将编写的代码⽂件保存为hello.asm,存于D:\masm5。
《x86汇编语言:从实模式到保护模式》配套代码清单
![《x86汇编语言:从实模式到保护模式》配套代码清单](https://img.taocdn.com/s3/m/832dd0e9951ea76e58fafab069dc5022aaea46b4.png)
《x86汇编语⾔:从实模式到保护模式》配套代码清单c05_mbr.asm;代码清单5-1;⽂件名:c05_mbr.asm;⽂件说明:硬盘主引导扇区代码;创建⽇期:2011-3-3121:15mov ax,0xb800;指向⽂本模式的显⽰缓冲区mov es,ax;以下显⽰字符串"Label offset:"mov byte [es:0x00],'L'mov byte [es:0x01],0x07mov byte [es:0x02],'a'mov byte [es:0x03],0x07mov byte [es:0x04],'b'mov byte [es:0x05],0x07mov byte [es:0x06],'e'mov byte [es:0x07],0x07mov byte [es:0x08],'l'mov byte [es:0x09],0x07mov byte [es:0x0a],' 'mov byte [es:0x0b],0x07mov byte [es:0x0c],"o"mov byte [es:0x0d],0x07mov byte [es:0x0e],'f'mov byte [es:0x0f],0x07mov byte [es:0x10],'f'mov byte [es:0x11],0x07mov byte [es:0x12],'s'mov byte [es:0x13],0x07mov byte [es:0x14],'e'mov byte [es:0x15],0x07mov byte [es:0x16],'t'mov byte [es:0x17],0x07mov byte [es:0x18],':'mov byte [es:0x19],0x07mov ax,number ;取得标号number的偏移地址mov bx,10;设置数据段的基地址mov cx,csmov ds,cx;求个位上的数字mov dx,0div bxmov [0x7c00+number+0x00],dl ;保存个位上的数字;求⼗位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x01],dl ;保存⼗位上的数字;求百位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x02],dl ;保存百位上的数字div bxmov [0x7c00+number+0x03],dl ;保存千位上的数字;求万位上的数字xor dx,dxdiv bxmov [0x7c00+number+0x04],dl ;保存万位上的数字;以下⽤⼗进制显⽰标号的偏移地址mov al,[0x7c00+number+0x04]add al,0x30mov [es:0x1a],almov byte [es:0x1b],0x04mov al,[0x7c00+number+0x03]add al,0x30mov [es:0x1c],almov byte [es:0x1d],0x04mov al,[0x7c00+number+0x02]add al,0x30mov [es:0x1e],almov byte [es:0x1f],0x04mov al,[0x7c00+number+0x01]add al,0x30mov [es:0x20],almov byte [es:0x21],0x04mov al,[0x7c00+number+0x00]add al,0x30mov [es:0x22],almov byte [es:0x23],0x04mov byte [es:0x24],'D'mov byte [es:0x25],0x07infi: jmp near infi ;⽆限循环number db 0,0,0,0,0times 203 db 0db 0x55,0xaac06_mbr.asmjmp near startmytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07number db 0,0,0,0,0start:mov ax,0x07c0;设置数据段基地址mov ds,ax ;ds寄存器⼀般保存数据段基地址mov ax,0xb800;设置附加段基地址mov es,ax ;这⾥附加段指向显存位置,存放在es寄存器中cld ;将⽅向标志位DF清零,以指⽰传送是负⽅向的,与此相对应的指令是stdmov si,mytext ;movsw指令原始数据串需要存放在ds:si位置,⽬的地址为es:di,因为ds⽬前指⽰的是当前代码段基地址地址,因此只要把偏移mytext存⼊si寄存器即可mov di,0;当前es指⽰显存起始位置,因此只要把偏移0存⼊di即可mov cx,(number-mytext)/2;实际上等于13,cx作为计数器,每进⾏⼀次rep指令cx-1rep movsw ;⼀次传送⼀个字(两个字节);得到标号所代表的偏移地址mov ax,number ;此代码⽬的旨在显⽰number的偏移地址;计算各个数位mov bx,ax ;bx指向当前number偏移地址mov cx,5;循环次数mov si,10;除数digit:xor dx,dx ;dx(被除数⾼16位)清零div si ;除法mov [bx],dl ;保存数位;为什么这⾥不⽤加0x7c00了?inc bx ;bx⾃加1,指向下⼀个内存单元,number⼀共定义了5个字节内存单元loop digit;显⽰各个数位mov bx,numbermov si,4show:mov al,[bx+si];从后往前显⽰add al,0x30mov ah,0x04mov [es:di],axadd di,2dec sijns show ;上⼀条指令符号位为SF=0(结果为⾮负)时跳转mov word [es:di],0x0744jmp near $ ;⽆限循环times 510-($-$$) db 0;512字节减去之后两个db指令=510字节,$当前指令偏移,$$当前代码段起始位置,填充字节0(db 0)db 0x55,0xaac07_mbr.asmjmp near startmessage db '1+2+3+...+100='start:mov ax,0x7c0;设置数据段的段基地址mov ds,axmov ax,0xb800;设置附加段基址到显⽰缓冲区mov es,ax;以下显⽰字符串mov si,messagemov di,0mov cx,start-message@g:mov al,[si];因为这是硬盘主引导扇区代码,因此被加载到0x7c00,[si]=[ds:si],就是相对于代码段开头的相对偏移,这个相对偏移就是标签message的值mov [es:di],alinc di ;di⽤做显存段地址的相对偏移,字符内容信息放在低⼀个字节mov byte [es:di],0x07inc di ;字符显⽰信息放在⾼⼀个字节inc si ;si⽤作寻址字符串相对偏移loop @g;以下计算1到100的和xor ax,ax ;清空ax寄存器,存放结果mov cx,1@f:add ax,cxinc cx ;cx做累加器cmp cx,100jle @f ;⼩于等于时跳转;以下计算累加和的每个数位xor cx,cx ;设置堆栈段的段基地址mov ss,cxmov sp,cx ;堆栈段指针和段基址都在0x0000处,堆栈段从⾼地址向低地址⽣长mov bx,10xor cx,cx@d:inc cx ;压栈中⽤cx记录⼀共压⼊栈元素个数,以便之后出栈时能及时停⽌popxor dx,dx ;被除数[dx:ax]div bx ;除数bxor dl,0x30;余数在dx中,但是余数最多到9,因此在dl中就够了,加0x30得到ASCII码push dx ;dx中只有dl有意义,但是压栈的单位必须是字(两个字节)cmp ax,0jne @d ;循环跳出时,结果5050每⼀位被放在栈中;以下显⽰各个数位@a:pop dx ;出栈,栈顶元素是千位,百位,⼗位,个位mov [es:di],dlinc dimov byte [es:di],0x07inc diloop @a8086寻址⽅式总结:1.寄存器寻址 :mov ax,cx2.⽴即寻址 :add bx,0xf000 (⽬的操作数⽴即数寻址,源操作数寄存器寻址)3.直接寻址 :mov ax,[0x5c0f]4.基址寻址:利⽤基址寄存器bx/bp中的值作为偏移地址,其中bx默认段寄存器为ds(数据段),bp默认段寄存器为ss(堆栈段)。
80X86 32位汇编程序设计
![80X86 32位汇编程序设计](https://img.taocdn.com/s3/m/bab171f9aef8941ea76e05b2.png)
Calling Convention
●
Windows ABI
Windows 定义了 3 种 Call Convention
–
C calling convention (__cdecl)
●
编译器默认的 calling convention WinAPI 的 calling convention 不常用
– –
●
387 浮点运算指令 (80 位 )
80x86 指令集概述
●
必须学习的指令
–
基本指令 SSE/SSE2/SSE3 特权指令 387 , MMX , 3DNow
● ●
●
有兴趣可以选学的指令
– –
●
不太值得学习的指令
–
将要被 SSE 系列指令淘汰 387 指令非常难用
80x86 处理器模式
32 位汇编与 16 位汇编的区别
80X86 32 位汇编程序设计
仲力 沈英哲 2006.4.21
Outline
●
80x86 指令概述 Windows 下的 32 位汇编
–
●
ABI & Examples
●
386 Linux 下的汇编 Optimization Guide x86-64(AMD64, Intel EMT64) Advanced topics and bibliography
– – –
●
标准 C 库 libc(printf, ...) Win32API POSIX API
Application Binary Interface
●
为了能和 C 语言互相调用,汇编程序必须符合 OS 规定的 ABI 规范。 ABI 规范一般包括
linux x86 elf _start函数反汇编详解
![linux x86 elf _start函数反汇编详解](https://img.taocdn.com/s3/m/ebd03c66182e453610661ed9ad51f01dc381576a.png)
linux x86 elf _start函数反汇编详解_start函数是ELF(Executable and Linkable Format)可执行文件的入口点,它被用作程序的起始位置。
在Linux x86环境下,_start函数是由汇编语言编写的。
下面是一个简单的_start函数的汇编代码:```assemblyglobal _startsection .datahello db "Hello, World!",10len equ $-hellosection .text_start:; write syscallmov eax, 4mov ebx, 1mov ecx, hellomov edx, lenint 0x80; exit syscallmov eax, 1xor ebx, ebxint 0x80```下面是_start函数的反汇编详解:1. `_start:` 标签:这是函数的入口点。
2. `mov eax, 4`:将系统调用号4(write)存储到寄存器eax中。
3. `mov ebx, 1`:将文件描述符1(标准输出)存储到寄存器ebx中。
4. `mov ecx, hello`:将hello变量的地址存储到寄存器ecx中。
5. `mov edx, len`:将len变量的值存储到寄存器edx中,len表示要写入的字节数。
6. `int 0x80`:使用软中断指令触发内核执行系统调用。
7. `mov eax, 1`:将系统调用号1(exit)存储到寄存器eax中。
8. `xor ebx, ebx`:将寄存器ebx设置为0,表示正常退出。
9. `int 0x80`:使用软中断指令触发内核执行系统调用。
这段代码的作用是向标准输出打印"Hello, World!",然后退出程序。
在Linux x86环境下,系统调用的参数传递通过寄存器进行,系统调用号存储在eax寄存器中,参数依次存储在ebx、ecx、edx等寄存器中。
X86平台下用汇编写HelloWorld
![X86平台下用汇编写HelloWorld](https://img.taocdn.com/s3/m/c3c9090cdf80d4d8d15abe23482fb4daa58d1df6.png)
X86平台下⽤汇编写HelloWorld⾸先需要安装⼀个汇编器,我⽤的是Nasm,这个汇编器在Linux下安装还是很简单的。
Nasm下载地址在下载之后对其进⾏解压,然后进⼊到其⽬录下,会发现有configure⽂件,接下来相信对于熟悉Linux的同学就知道该怎么办了。
输⼊./configure然会待其执⾏完成后,会发现在⽬录下⽣成了⼀个Makefile⽂件,这是输⼊make命令,就可以完成对Nasm的编译了然后进⼊root,输⼊make install对Nasm进⾏安装即可了。
然后如果你的机器上没有gcc的话可以安装下gcc这⾥⾃⼰去搜索引擎找就⾏了,因为我这⾥已经安装了gcc所以这⾥不再多说。
接下来就可以编写helloworld的汇编代码了,我这⾥参考的是维基百科上的代码⽰例section .datamsg db 'Hello, world!',0xAlen equ $-msgsection .textglobal _start_start:mov edx,lenmov ecx,msgmov ebx,1mov eax,4int 0x80mov ebx,0mov eax,1int 0x80然后将编辑的⽂件保存,起始后缀名没什么关系,后缀名在Linux下只是给⼈看的罢了,保存之后,输⼊nasm -f elf32 ⽂件名,然后会发现在该命令执⾏完成后⽣成了⼀个⽂件名.o的⽂件,然后输⼊ld ⽂件名.o -o ⽂件名执⾏完成后,就⽣成了我们平时使⽤的可以执⾏⽂件。
此时输⼊./⽂件名就会出现Hello World了。
⾃⼰在看了下汇编的东西后,⾃⼰⽤AT&T的汇编格式写出了⼀个Hello World,虽然很简单,但是对于⼀直想⾃学下汇编,但是⼀直也没学的我来说,还是觉得⾃⼰能独⽴写出⼀个⼩⼩的汇编程序感到很兴奋。
.equ SYS_WRITE, 4.equ SYS_EXIT, 1.equ SYSCALL, 0x80.equ STDOUT, 1.equ STR_LEN 12.section .datastr:.ascii "hello world\n\0".section .text.globl _start_start:movl %esp, %ebpsubl $4, %espmovl $str, -4(%ebp)movl $SYS_WRITE, %eaxmovl $STDOUT, %ebxmovl -4(%ebp), %ecxmovl $STR_LEN, %edxint $SYSCALLmovl $SYS_EXIT, %eaxmovl $0, %ebxint $SYSCALL调⽤动态链接库实现HelloWorld.section .datastr:,ascii "hello world\n\0".section .text.globl _start_start:pushl $strcall printfpushl $0call exit这样,该程序在汇编时仍然和之前⼀样使⽤ as helloworld.s -o helloworld.o,但是在进⾏链接时却需要做⼀些改变应该使⽤如下的⽅式进⾏: ld -dynamic-linker /lib/ld-linux.so.2 -o helloworld helloworld.o -lc这样编译就可以完成了。
C++内嵌汇编示例详解
![C++内嵌汇编示例详解](https://img.taocdn.com/s3/m/3769e34276232f60ddccda38376baf1ffc4fe342.png)
C++内嵌汇编⽰例详解⽬录汇编语⾔汇编语⾔的特点1.内嵌汇编介绍2.汇编版本Hello, World!3.内联汇编A+B汇编语⾔汇编语⾔是⼀种功能很强的程序设计语⾔,也是利⽤了计算机所有硬件特性并能直接控制硬件的语⾔。
在汇编语⾔中,⽤助记符(Memoni)代替操作码,⽤地址符号(Symbol)或标号(Label)代替地址码。
这样⽤符号代替机器语⾔的⼆进制码,就把机器语⾔变成了汇编语⾔。
汇编语⾔⽐机器语⾔易于读写、调试和修改,同时也具有机器语⾔执⾏速度快、占⽤内存空间少等优点。
但在编写复杂程序时,相对⾼级语⾔来说汇编语⾔代码量较⼤,⽽且汇编语⾔依赖于具体的机型,不能通⽤,因此不能直接在不同处理机型之间移植。
虽然其移植性不好,但效率⾮常⾼,针对计算机特定硬件⽽编制的汇编语⾔程序,能准确地发挥计算机硬件的功能和特长,程序精炼⽽质量⾼,所以汇编语⾔⾄今仍是⼀种常⽤⽽强有⼒的底层开发语⾔。
汇编语⾔的特点汇编语⾔指令使⽤⼀些具有相应含义的助忆符来表达的,所以,它要⽐机器语⾔容易掌握和运⽤。
但因为要直接使⽤CPU资源,所以相对⾼级程序设计语⾔来说它⼜显得相对复杂。
汇编语⾔程序归纳起来⼤概有以下⼏个主要特点。
1. 与硬件相关:汇编语⾔指令是指机器指令的⼀种符号表⽰,⽽不同类型的CPU有不同的机器指令系统,也就有不同的汇编语⾔,所以汇编语⾔程序与机器有着密切的关系。
也就是说,不同型号的CPU之间是⽆法通⽤相同汇编代码的,因此导致汇编语⾔的移植性和通⽤性降低,这是汇编语⾔天⽣的缺陷。
2. 保持了机器语⾔的优点,具有直接和简捷的特点:正因为汇编语⾔有“与机器相关性”的特性,程序员⽤汇编语⾔编写程序时,可充分发挥⾃⼰的聪明才智,对机器内部的各种资源进⾏合理的安排,让它们始终处于最佳的使⽤状态,这样做的最终效果就是程序的执⾏代码短,执⾏速度快,所以,汇编语⾔是⾼效的程序设计语⾔。
另外汇编语⾔可有效地访问、控制计算机的各种硬件设备,如磁盘、存储器、CPU、I/O端⼝等,实现资源利⽤的最⼤化。
汇编Helloworld
![汇编Helloworld](https://img.taocdn.com/s3/m/0d3574cd28ea81c758f578cf.png)
实验一
一、实验目的
通过编写经典“HELLO WORLD”程序,运用DEBUG.EXE程序查看程序运行时的状态,对程序运行时的内存状况和寄存器状况进行监视,掌握汇编语言的编写过程和方法。
二、实验内容
1.编写程序显示字符串“Hello World!”,掌握汇编语言的编写过程以及汇编语言的基本结构。
2.掌握通过DEBUG.EXE调试程序的基本方法,进一步明确编译、链接的相关概念。
三、实验结果(将源程序、汇编、链接、运行程序全部截图)
1.编辑源程序
用文本编辑工具编辑源程序,内容如下:
data segment
stringdb "Hello World!",0dh,0ah,24h
data ends
code segment
assumecs:code,ds:data
start: movax,data
movds,ax
mov ah,09h
movdx,offset string
int 21h
mov ah,4ch
int 21h
code ends
end start
将文件另存为.asm格式,放置到与masm同一文件夹下。
2.汇编源程序
用汇编器MASM汇编源程序生成目标代码文件
3. 连接目标程序文件
4.调试可执行程序
5.运行结果
/s/blog_62b339a70100npxh.html。
深入浅出HelloWorld1
![深入浅出HelloWorld1](https://img.taocdn.com/s3/m/4143330dfbd6195f312b3169a45177232f60e496.png)
深⼊浅出HelloWorld1还有源码的下载地址链接,同时还要感谢那些⽹上的勤勤恳恳写blog的bloger们。
Hello World是学习程序设计语⾔的第⼀个程序浅出 Hello World。
我们试图分析⾃linux上的Hello World运⾏的整个过程,主要包括下⾯的⼏个过程:1.hello程序的编译链接过程和hello上可执⾏⽂件格式2.hello可执⾏程序的加载及如何开始执⾏3.hello在内存中镜像4.寻址5.调度程序6.内存管理7.系统调⽤8.hello程序卸载⾸先是hello可执⾏⽂件的连接过程,然后hello可执⾏⽂件如何被加载到内存中,然后从那⾥开始执⾏?在执⾏的过程中,可能需要寻址,如何实现?可能的内核调度如何实现?内存管理如何实现?系统调⽤如何实现?hello程序执⾏完成之后,kernel 执⾏了那些清理的⼯作?hello程序编译链接过程和hello可执⾏elf⽂件格式vim hello.c#include <stdio.h>int main (int atgc, char* argv[]){printf ("Hello World");return 0;}gcc hello.c -o hello⾸先在Text Editor中编辑hello的source code,gcc在编译source code时,先执⾏预处理,完成将source code中的宏定义展开de 等功能,这个过程是由cpp完成,最终⽣成hello.i⽂件,然后由complier编译成hello.s,这个过程是由ccl完成,然后使⽤as将上⾯的hello.s编译成hello.o,最后使⽤ld将上⾯⽣成的hello.o连接成可执⾏⽂件hello。
我们可以使⽤下⾯的命令来观察⽣成的hello程序:file hellohello: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux2.6.15, not strippedldd hellolinux-gate.so.1 => (0xb7f01000)libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0xb7d89000)/lib/ld-linux.so.2 (0xb7f02000)objdump -x hellohello: file format elf32-i386helloarchitecture: i386, flags 0x00000112:EXEC_P, HAS_SYMS, D_PAGEDstart address 0x08048310Program Header:PHDR off 0x00000034 vaddr 0x08048034 paddr 0x08048034 align 2**2filesz 0x00000100 memsz 0x00000100 flags r-xINTERP off 0x00000134 vaddr 0x08048134 paddr 0x08048134 align 2**0filesz 0x00000013 memsz 0x00000013 flags r--LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12filesz 0x000004c0 memsz 0x000004c0 flags r-xLOAD off 0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**12filesz 0x00000108 memsz 0x00000110 flags rw-DYNAMIC off 0x00000f20 vaddr 0x08049f20 paddr 0x08049f20 align 2**2filesz 0x000000d0 memsz 0x000000d0 flags rw-NOTE off 0x00000148 vaddr 0x08048148 paddr 0x08048148 align 2**2filesz 0x00000020 memsz 0x00000020 flags r--STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2filesz 0x00000000 memsz 0x00000000 flags rw-RELRO off 0x00000f0c vaddr 0x08049f0c paddr 0x08049f0c align 2**0filesz 0x000000f4 memsz 0x000000f4 flags r--反汇编:objdump -d hellohello: file format elf32-i386Disassembly of section .init:08048294 <_init>:8048294: 55 push %ebp8048295: 89 e5 mov %esp,%ebp8048297: 53 push %ebx8048298: 83 ec 04 sub $0x4,%esp804829b: e8 00 00 00 00 call 80482a0 <_init+0xc>80482a0: 5b pop %ebx80482a1: 81 c3 54 1d 00 00 add $0x1d54,%ebx80482a7: 8b 93 fc ff ff ff mov -0x4(%ebx),%edx80482ad: 85 d2 test %edx,%edx80482af: 74 05 je 80482b6 <_init+0x22>80482b1: e8 1e 00 00 00 call 80482d4 <__gmon_start__@plt>80482b6: e8 e5 00 00 00 call 80483a0 <frame_dummy>80482bb: e8 a0 01 00 00 call 8048460 <__do_global_ctors_aux>80482c0: 58 pop %eax80482c1: 5b pop %ebx80482c2: c9 leave80482c3: c3 retDisassembly of section .plt:...经过上⾯的观察,产⽣下⾯的疑问:ldd链接的⽂件的作⽤是什么?链接程序时发⽣了什么?可执⾏⽂件的格式是怎样的?为了解决上⾯的问题还是得⾸先了解⼀下计算机程序的基础知识。
Cocos2d-x 的“HelloWorld” 深入分析完整版
![Cocos2d-x 的“HelloWorld” 深入分析完整版](https://img.taocdn.com/s3/m/4fb938f44693daef5ef73d1e.png)
Cocos2d-x 的“HelloWorld” 深入分析不能免俗,一切都从“ HelloWorld! ”开始. 打开HelloWorld 工程, 里面有两个文件目录Classes 和win32 。
Classes 下有HelloWorldScene.h/cpp ,AppDelegate.h/cpp.win32 下有main.h/cpp首先看一下win32 目录下的main.h, 其中定义了使用win32 平台进行编译的宏和一些Windows 编程头文件。
#ifndef __MAIN_H__#define __MAIN_H__//定义使用WIN32平台进行编译的宏#define WIN32_LEAN_AND_MEAN// 所用到的Windows编程所用头文件#include <windows.h>#include <tchar.h>// Cocos的C语言头文件#include "CCStdC.h"#endif // __MAIN_H__再打开main.cpp.//加入main.h头文件#include "main.h"//加入使用的AppDelegate类头文件#include "../Classes/AppDelegate.h"//WinMain主函数int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){//UNREFERENCED_PARAMETER用于在VC编译器下告知编译器,不必检测改变量是否使用的警告。
UNREFERENCED_PARAMETER(hPrevInstance);UNREFERENCED_PARAMETER(lpCmdLine);// 创建一个Cocos2d-x程序实例AppDelegate app;// 运行程序实例return cocos2d::CCApplication::sharedApplication().run();}代码看着就这么几行,好像非常简单。
汇编2.汇编版本的helloworld
![汇编2.汇编版本的helloworld](https://img.taocdn.com/s3/m/afacfa39bc64783e0912a21614791711cc79794e.png)
汇编2.汇编版本的helloworld寻址⽅式⽴即数寻址寄存器寻址存储器寻址直接寻址 : mov ax, [ 01000h ];直接在[]内给出⼀个内存地址寄存器间接寻址: mov ax ,[si]; 在[]以寄存器的值给出内存地址.寄存器相对寻址: mov ax,[si+0ch]在[]以寄存器的值和⼀个数相加之后作为内存地址.struct MyStruct{int n1;char ch;int n2;};MyStruct stc;stc.n1 = 0;stc.n2 = 10;//假设stc的内存⾸地址是0x1000// 以汇编形式访问结构体字段:mov bx , 0x1000; // bx保存了结构体⾸地址mov [bx+0] , 0; //stc.n1mov [bx+8] , 10;//stc.n2基址变址寻址: mov ax,[si+bx]使⽤两个寄存器相加之和作为内存地址char szBuff[10];for(int i = 0; i<10;++i){szBuff[i] = 0;}// 假设szBuff⾸地址是0x1000mov si , 0x1000;xor bx,bx;for(int i =0;i<10;++i){// szBuff[i] = 0;mov [si+bx] , 0;inc bx;}相对基址变址寻址: mov ax,[si+bx+0ch]使⽤[]内的表达式的相加之和作为内存地址.在16位汇编中, 要使⽤存储器寻址的时候, 如果希望⽤寄存器寻址, 那么只能使⽤si,di,bx,bp寄存器, 然后这些寄存器不能任意组合.条件跳转指令有有符号跳转和⽆符号跳转之分.常见条件跳转指令:有符号跳转:jg⼤于jge⼤于等于jl⼩于jle⼩于等于⽆符号跳转ja⼤于, cf0 且 zf0则跳转jae⼤于等于 , cf ==0 则跳转jb⼩于, cf==1则跳转jbe⼩于等于, cf1 或 zf1则跳转不区分符号跳转je zf==1 则跳转jne zf==0 则跳转32位汇编第⼀个汇编项⽬.386 ;告诉汇编器, 使⽤32位汇编的语法来编译.model flat , stdcall ;默认使⽤平坦模式,默认使⽤stdcall的调⽤约定option casemap:none.code ; 定义⼀个代码段sldkfjlaskdjfmain:retend sldkfjlaskdjfmain; 指定程序⼊⼝点end ; 结束代码段1. 每个asm源码⽂件中都以下⾯的指令打头:.386 ;告诉汇编器, 使⽤32位汇编的语法来编译.model flat , stdcall ;默认使⽤平坦模式,默认使⽤stdcall的调⽤约定option casemap:none2. 必须⾃⼰定义⼀个代码段, 定义代码段使⽤.code伪指令 , 汇编指令就写在.code和end之间3. 程序必须要有⼀个⼊⼝点.在C语⾔中, 就固定了是main函数. 在masm⾥⾯, 可以在代码段中使⽤end 标签的⽅式来指定⼊⼝点.4. 数据的定义必须放在数据段, 数据段使⽤.data指令来定义..data ; 定义数据段.const ; 定义常量数据(不可修改的数据).code ; 定义代码段1. 在数据段中定义数据, 可以使⽤d系列指令.datach db 'a' ; 相当于 char ch='a';buff db 0,0,0,0 ; 相当于 char buff[]={0,0,0,0};str db "hello" , 0; 相当于 char str[]={'h','e','l','l','o' , 0 }; 也就是说,这⾥不会⾃动加上字符串结束符'\0'str2 db "hello\n" , 0; 在masm中没有转义字符.str2 db "hello", 0ah , 0 ; 0ah是'\n'; 其它类型var1 dw 100 ; word类型var2 dd 100 ; dword类型; dup⽤于重复定义数据 , dup前是⼀个重复的次数, dup圆括号内是需要重复的初始化值.arr dd 100 dup(0) ; int arr[100]={0};.386 ;告诉汇编器, 使⽤32位汇编的语法来编译.model flat , stdcall ;默认使⽤平坦模式,默认使⽤stdcall的调⽤约定option casemap:none ; 不区分⼤⼩写; 包含名为`msvcrt.inc`头⽂件(c语⾔的所有库函数)include msvcrt.inc; 包含库⽂件includelib msvcrt.lib;include windows.inc;include user32.inc;includelib user32.lib.datag_str db "hello world",0dh,0ah, 0 ; \r\n==0d0a.code ; 定义⼀个代码段main:push offset g_str;call crt_printfadd esp , 4retend main; 说明程序⼊⼝点end ; 结束代码段汇编程序基础三⼤程序结构顺序结构选择结构在c中, if else , switch循环结构int n =0;scanf("%d",&n);if( n == 1){printf("星期⼀\n");}else if(n==2){printf("星期⼆\n");}else if(n==3){printf("星期三\n");}汇编版本.datan dd 0 ; 定义⼀个全局变量, 名字为n .code_main:cmp n , 1je _FLAG1cmp n , 2je _FLAG2cmp n , 3je _FLAG3_FLAG1:printf("星期⼀\n");jmp _ENDIF_FLAG2:printf("星期⼆\n");jmp _ENDIF_FLAG3:printf("星期三\n");_ENDIF:end _mainendswitch( n ){case 1: printf("星期1\n");break; case 2: printf("星期2\n");break; case 3: printf("星期3\n");break; }汇编版本1(和if-else的⼀样)汇编版本1 : 使⽤跳转表.386 ;告诉汇编器, 使⽤32位汇编的语法来编译.model flat , stdcall ;默认使⽤平坦模式,默认使⽤stdcall的调⽤约定option casemap:none ; 不区分⼤⼩写; 包含名为`msvcrt.inc`头⽂件(c语⾔的所有库函数)include msvcrt.inc; 包含库⽂件includelib msvcrt.lib;include windows.inc;include user32.inc;includelib user32.lib.datag_str db "hello world",0dh,0ah, 0 ; \r\n==0d0astr1 db "星期⼀",0dh,0ah,0str2 db "星期2",0dh,0ah,0str3 db "星期3",0dh,0ah,0.code ; 定义⼀个代码段main:.codejmp beingjmptable dd _FLAG1,_FLAG2,_FLAG3 ; 在code段定义数据being:mov eax , 1 ; ;dec eax;jmp [jmptable+eax*4]; 根据eax的值,来跳转不同的位置._FLAG1:invoke crt_printf, offset str1;jmp _ENDIF_FLAG2:invoke crt_printf , offset str2;jmp _ENDIF_FLAG3:invoke crt_printf ,offset str1;_ENDIF:end main; 说明程序⼊⼝点end ; 结束代码段int i =0;while (i < 10){++i;}汇编版本1:xor eax,eax ; 使⽤eax寄存器作为i_WHILE:cmp eax , 10 ;jge _ENDWHILEinc eaxjmp _WHILE_ENDWHILE:汇编版本2 : loop循环, 该指令使⽤ecx作为默认寄存器, 保存着循环次数, loop指令执⾏之后, 会判断ecx的值是否等于0 , 如果等于了,就不会跳转, 如果没有等于, 就先将ecx递减1, 然后跳转mov ecx , 10;_WHILE:loop _WHILE ;函数结构函数调⽤和函数返回语句call,retcall ⽬标地址 - 调⽤函数的指令会将call指令的下⼀条指令的地址push到栈中.跳转到⽬标地址.ret返回指令其实就是pop eip ,call指令将⼀个返回地址保存到栈中, ret就默认把栈中的地址取出设置到eip这样就能回调函数的调⽤点了.ret 字节数 - 返回时,顺便平衡指定字节栈空间.定义函数通过ret指令来回到函数的调⽤点.调⽤函数函数的传参是通过栈来完成的.调⽤函数之前, 先将实参压⼊栈中.进⼊函数之后, 就可以从栈中取出参数了.在传参的时候, 是从右往左依次将参数⼊栈,还是从左往右,需要有⼀个函数调⽤约定调⽤约定名传参顺序栈平衡者_cdecl - C调⽤约定从右往左函数外部_stdcall - 标准调⽤约定从右往左函数内部_thiscall - 对象调⽤从右往左,this指针保存到ecx寄存器函数内部fastcall - 快速调⽤约定前两个参数通过ecx,edx来传递, 后⾯的参数从右往左依次⼊栈传递函数内部通过call + 函数地址完成调⽤在函数内部定位栈中的参数。
用19种编程语言写Hello World
![用19种编程语言写Hello World](https://img.taocdn.com/s3/m/134aa9d16f1aff00bed51e67.png)
Hello World 程序是每一种编程语言最基本的程序,通常初学者都是从这段代码开始编程语言的学习,俨然成为了编程的一种象征。
于是突发奇想罗列一些程序语言的Hello World代码,以激励自己努力学习,同时激发广大的社会主义青年学习编程的兴趣,用科学技术带领亿万同胞脱离苦海……1、C无论编程技术怎么变化,始终没有一种编程语言可以替代C语言,只少目前为止是这样。
#includeint main(void){printf("Hello, world!\n");return0;}2、JavaSun公司开发的跨平台语言,我曾经用Java写过一个很烂的Android手机应用程序,还是别提了……public class Hello{public static void main(String[] args){System.out.println("Hello, world!");}}3、C++C++起初作为C语言的加强版,但后来强大到可以作为独立语言了,只是它强大得太复杂了,所以有些程序员讨厌它,比如我……以至于出现“21天教你学会C++”这样的文章……#includeint main(){std::cout<<"Hello, world!"<< std::endl;return0;}4、PHPPHP一般作为服务器脚本语言来构建网站后台,比如Wordpress博客程序就是使用PHP编写的。
<?phpecho'Hello, world!';?>5、Basic看名字就知道是给初学者使用的语言,不过我从来没学过……PRINT"Hello, world!"END6、C#C#语言,其中“#”的创意来源于音乐中的升调符号,读作“sharp”,表示技术进一步提升之意。
x86汇编指令
![x86汇编指令](https://img.taocdn.com/s3/m/26180f69a45177232f60a236.png)
简明X86汇编语言教程原创:司徒彦南2002年4月8日徐远超于2010-02-25收集整理 2010-03-10第2次补充 2010-03-25第3次补充目录第Ο章 写在前面 (2)第一章汇编语言简介 (3)第二章认识处理器 (4)2.1 寄存器 (4)2.2 使用寄存器 (6)第三章操作内存 (12)3.1 实模式 (12)3.2 保护模式 (16)3.3 操作内存 (19)3.4 串操作 (21)3.5 关于保护模式中内存操作的一点说明 (22)3.6 堆栈 (23)本章小结 (25)第四章利用子程序与中断 (25)4.1 子程序 (25)4.2 中断 (31)第五章编译优化概述 (34)5.1 循环优化:强度削减和代码外提 (36)5.2 局部优化:表达式预计算和子表达式提取 (37)5.3 全局寄存器优化 (38)5.4 x86体系结构上的并行最大化和指令封包 (40)5.5 存储优化 (42)第六章 Linux X86汇编程序设计 (46)6.1编译和链接 (46)6.2基本示例 (46)第七章 X86汇编指令集汇总 (47)一.数据传输指令 (47)二、算术运算指令 (49)三、逻辑运算指令 (49)四、串指令 (50)五、程序转移指令 (50)六、伪指令 (52)七、寄存器 (52)八、位操作指令,处理器控制指令 (52)九、FPU instructions (54)第八章 GCC内联汇编基础 (54)1. GCC汇编格式 (55)2.内联汇编基本形式 (56)3. 扩展形式内联汇编 (56)4. 深入constra (59)5.结束语 (63)第Ο章写在前面我不想夸大或者贬低汇编语言。
但我想说,汇编语言改变了20世纪的历史。
与前辈相比,我们这一代编程人员足够的幸福,因为我们有各式各样的编程语言,我们可以操作键盘、坐在显示器面前,甚至使用鼠标、语音识别。
我们可以使用键盘、鼠标来驾驭“个人计算机”,而不是和一群人共享一台使用笨重的继电器、开关去操作的巨型机。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
V | | V | |
低 + .... + 低 + .... +
图一 图二
下面从main函数开始单步分析每一句话,并跟踪堆栈状态。
初始状态,堆栈状态如图一:
高 +----------------+ <-- esp (栈顶) 高 +----------------+
| | | | | |
a = 3, 将a的值存入堆栈(加载到内存中)。
31 movl $4, -12(%ebp)
b = 4, 将b的值存入堆栈(加载到内存中)。
32 movl -12(%ebp), %eax
33 movl %eax, 4(%esp)
将b的值调入寄存器,并且入栈,为调用add函数准备参数。
10 addl %edx, %eax
相加,结果存入eax寄存器。
18 .string "Hello World!"
19 .text
20 .globl main
21 .type main, @function
22 main:
23 leal 4(%esp), %ecx
24 andl $-16, %esp
| +----------------+ | +----------------+ <-- esp
| | | | | |
图三
29 subl $36, %esp
esp向下移动36字节,留出空间给局部变量使用,每个存储单元4字节,故共9格。这里预留的空间有些多,在后续的分析中会发现,很多空都没用上。在第四部分的优化后的代码中也可以看到,36被优化成了20,预留的空间正好用满。
30 movl $3, -8(%ebp)
2
3 int add(int a, int b){
4 return (a+b);
5 }
6
7 int main(int argc, char **argv){
8 int a, b, c;
9 a = 3;
10 b = 4;
11 c = add(a, b);
| +----------------+ | + 若干 +
| | | | | |
基于x86的Hello World汇编代码分析
(AT&T汇编风格)
本文通过对由gcc对简单C语言代码编译生成的汇编码进行逐句分析解读,来学习x86的汇编结构和堆栈机制。文章涉及细节较多,难免出错,望读者不吝赐教!
一、代码
C语言代码:
/* file: hello.c */
1 #include <stdio.h>
| +----------------+ <-- esp
| | old esp+4 | 28 pushl %ecx (ecx =old esp + 4)
| +----------------+
下面进入add函数代码。
6 pushl %ebp
将ebp值压栈保存。
7 movl %esp, %ebp
移动ebp至当前esp位置。
8 movl 12(%ebp), %edx
9 movl 8(%ebp), %eax
将两个参数加载到寄存器。
将ecx所指地址(也就是程序开始时esp所指位置,如图一所示)的内容压栈。这个内容是eip。关于这句的用途,后面有详细解释。
26 pushl %ebp
将ebp压栈,保存ebp的值,以便在退出函数时恢复。
27 movl %esp, %ebp
将ebp移动到esp的位置。
28 pushl %ecx
将ecx的值压栈,保存,在退出函数时,通过这个值来恢复esp的初始值。
现在,堆栈状态如图三:
高 +----------------+ <-- old esp
| | |
| +---- 若干 ----+
44 movl $0, %eax
45 addl $36, %esp
46 popl %ecx
47 popl %ebp
48 leal -4(%ecx), %esp
49 ret
50 .size main, .-main
2 .text
3 .globl add
4 .type add, @function
5 add:
6 pushl %ebp
7 movl %esp, %ebp
8 movl 12(%ebp), %edx
9 movl 8(%ebp), %eax
12 printf("a+b=%d/n", c);
13 printf("Hello World!/n");
14 return 0;
15 }
16
gcc -S -ohello.s hello.c输出文件:
/* file: hello.s */
1 .file "hello.c"
38 movl -16(%ebp), %eax
39 movl %eax, 4(%esp)
40 movl $.LC0, (%esp)
41 call printf
42 movl $.LC1, (%esp)
43 call puts
25 pushl -4(%ecx)
26 pushl %ebp
27 movl %esp, %ebp
28 pushl %ecx
29 subl $36, %esp
30 movl $3, -8(%ebp)
31 movl $4, -12(%ebp)
10 addl %edx, %eax
11 popl %ebp
12 ret
13 .size add, .-add
14 .section .rodata
15 .LC0:
16 .string "a+b=%d/n"
17 .LC1:
51 .ident "GCC: (Ubuntu 4.3.2-1ubuntu12) 4.3.2"
52 .section .note.GNU-stack,"",@progbits
二、分析
下面对hello.s进行逐句分析。
第1行为gcc留下的文件信息;第2行标识下面一段是代码段,第3、4行表示这是add函数的入口,第5行为入口标号;6~12行为add函数体,稍后分析;13行为add函数的代码段的大小;14行指示下面是数据段;15~18行定义了main中要用到的两个字符串常量;19行同第二行,20、21行定义了main函数入口,22行为main入口标号。23行开始正式进入main函数,直至49行;50行为main函数代码段体积。51、52行为 gcc留下的信息。
32 movl -12(%ebp), %eax
33 movl %eax, 4(%esp)
34 movl -8(%ebp), %eax
35 movl %eax, (%esp)
36 call add
37 movl %eax, -16(%ebp)
23 leal 4(%esp), %ecx
将esp所指地址加4得到的地址存入ecx。
24 andl $-16, %esp
-16的补码为11...10000,这句话使esp指针下移若干位,新地址末四位是0,故按16字节对齐,如图二。对齐是为了加速CPU访存。
25 pushl -4(%ecx)
34 movl -8(%ebp), %eax
35 movl %eax, (%esp)
将a的值调入寄存器,并且入栈,为调用add函数准备参数。
36 call add
调用add函数。注意,在这里,call指令隐含执行了一条ush %eip的指令,记录当前代码段执行的位置。
| | |
| +----------------+
V | |
低 + .... +
| | eip | 25 pushl -4(%ecx)
| +----------------+ <-- ebp 27 movl %esp, %ebp
| | old ebp | 26 pushl %ebp (we don't know what old ebp is, but we have to backup it)
| | |
| +----------------+
| | |
| +----------------+