ubuntu16.04 GNU汇编学习笔记-环境搭建和简单示例

一)序言

   作为有着十几年开发经验的老程序员,自己一直对汇编比较“懵懂”,曾经购买过MASM这本书来学习,但是一直未能坚持和深入下去,等几年不看就完全忘记了。最近到了新的公司,对汇编,c编译,链接,运行内存等等都有了更高,更深的要求,自己也意识到这点,希望可以花一段时间来学习,掌握,精通汇编语言。最好的状态是看到c代码可以自动转换为汇编代码。

    我一直觉得一个新手刚刚进入一个新的领域,不要一开始就看那些深奥的框架知识,众多的语法说明,而是先写一些小程序,编译运行,看看效果,自己给自己设定一些小的功能实现,等这些完成后,在继续看框架和语法说明效果可能会更好一些。

二)开发环境搭建,验证

    因为工作中使用的是GNU GCC开发,所以这里也专注于此方向,操作系统是Ubuntu16.04 64位系统。

    目前我们一般开发还都是32位,而ubuntu16.04则是64位系统,这里需要我们按照一些系统组件开支持开发,百度的结果,这里不单独做转发说明。注意下面三个必须同时安装,只安装第三个会有问题。

ubuntu16.04(64位)兼容32位程序
sudo apt install libc6:i386
sudo apt install libstdc++6:i386
或者直接安装gcc-multilib解决问题(推荐使用此方法)
sudo apt install gcc-multilib

   汇编程序代码hello.s 代码来自https://blog.csdn.net/shallnet/article/details/45544271,非常感谢作者。

#hello.s sample program to print hello world information
.section .data    #数据段声明
msg:
    .ascii "hello world -00- !\n"    #要输出的字符串
    len=.-msg                        #字符串长度
 
.section .text    #代码段声明
# .global main
# main:
.global _start     #指定入口函数
 
_start:                                 #函数在屏幕上输出hello world!
    movl $len, %edx               #第三个参数: 字符串长度
    movl $msg, %ecx             #第二个参数: hello world!字符串
    movl $1, %ebx                  #第一个参数: 输出文件描述符
    movl $4, %eax                  #系统调用号sys_write
    int $0x80                            #调用内核功能
         
#下面为退出程序代码
    movl $0, %ebx                #第一个参数: 退出返回码
    movl $1, %eax                #系统调用sys_exit
    int $0x80                        #调用内核功能

 编译脚本:as_ld_run.sh

#!/bin/sh
rm hello.o hello
as -o hello.o hello.s
ld -o hello hello.o
./hello

运行结果:

hello world -00- !

 知识点:0)AS汇编的入口函数;1)汇编代码的最简单框架;2)汇编中调用linux系统调用的实现方法。

三)汇编里定义字符串,c语言里面显示此字符串功能实现

汇编代码addfunc.s

# addfunc.s
.code32
.section .data    #数据段声明
msg:
    .ascii "hello world 111111111111122222222233333333!"    #要输出的字符串
    len=.-msg                        #字符串长度
.section .text    #代码段声明

.global _start     #指定入口函数
.type addfunc, @function
.globl addfunc
addfunc:
    pushl   %ebp        # 因为该函数不影响ebx,edi、esi寄存器,所以开头和结尾没有包含它们。
    movl    %esp, %ebp

    pushl    $msg
    pushl    8(%ebp)
    call    strcpy
    addl    $16, %esp
    movl    $0, %eax
    popl    %ecx         #恢复ecx

    movl    %ebp, %esp
    popl    %ebp
    ret

c代码

#include <string.h>

extern int addfunc(char*);
int main(int argc, const char *argv[])
{
    int ret = 2;
    char *p = NULL;
    char str[128] = "";
    p = str;
    ret = addfunc(p);
    printf("The return value is %d str=%s strlen(p)=%d.\n", ret, p,strlen(p));
    return 0;
}

Makefile

# Makefile for linux as
 
CFLAGS= -Wall -g -m32
ASFLAGS= -gstabs --32
 
SRC_BIN=target_bin
 
SRC_C=$(wildcard *.c)
SRC_S=$(wildcard *.s)
 
SRC_OBJ=$(SRC_C:.c=.o)
SRC_OBJ+=$(SRC_S:.s=.o)
 
all: $(SRC_BIN)
 
$(SRC_BIN): $(SRC_OBJ)
    $(CC) -m32 -o $@ $(SRC_OBJ) 
 
clean:
    $(RM) $(SRC_OBJ) $(SRC_BIN) *~
.PHONY:
    all clean

运行命令和结果:

gaozh@T0:~/works/Application/c_assemblyfunc_str$ make clean&&make && ./target_bin 
rm -f main.o addfunc.o target_bin *~
cc -Wall -g -m32   -c -o main.o main.c
as -gstabs --32  -o addfunc.o addfunc.s
cc -m32 -o target_bin main.o addfunc.o 
The return value is 0 str=hello world 111111111111122222222233333333! strlen(p)=43.

知识点:1)64位系统编译32位汇编程序和32位C程序;2)汇编中自定字符串(符号常数)定义,使用;3)汇编中函数实现模板,进口和出口;4)汇编中strcpy API的调用,(未彻底搞清楚,寄存器与此api的关系)。

四)在第三步的基础上,增加汇编函数返回值表示字符串长度的功能实现

汇编代码:

# addfunc.s
.code32
.section .data    #数据段声明
msg:
    .ascii "hello world <111111111111122222222233333333!>"    #要输出的字符串
    len=.-msg                        #字符串长度
.section .text    #代码段声明

.global _start     #指定入口函数
.type addfunc, @function
.globl addfunc
addfunc:
    pushl   %ebp        # 因为该函数不影响ebx,edi、esi寄存器,所以开头和结尾没有包含它们。
    movl    %esp, %ebp

    movl    8(%ebp),%eax #取得C函数传过来的参数
    pushl   %ecx        #保护ecx,用作临时变量
    movl    (%eax),%ecx  #取得指针所指的内容

    pushl   $msg
    pushl   8(%ebp)
    call    strcpy
    addl    $16, %esp
    movl    $0, %eax

    popl    %ecx         #恢复ecx:w
    movl    $len, %eax

    movl    %ebp, %esp
    popl    %ebp
    ret

运行结果:

gaozh@T0:~/works/Application/c_assemblyfunc_str$ make clean&&make && ./target_bin 
rm -f main.o addfunc.o target_bin *~
cc -Wall -g -m32   -c -o main.o main.c
as -gstabs --32  -o addfunc.o addfunc.s
cc -m32 -o target_bin main.o addfunc.o 
The return value is 0 str=hello world 111111111111122222222233333333! strlen(p)=43.

总结:1)汇编函数中对唯一参数和函数返回值如何进行处理;

五)总结

1)两个例子都可以在预定环境下运行;

2)通过两个例子对汇编函数,函数参数,参数返回值有了一定的了解;

3)汇编中调用strcpy的实现,我是通过c代码实现,然后编译成.s文件做参考获得的代码,这将是后面很多功能实现的一个好的思路。

posted @ 2018-07-10 22:59  tankaro  阅读(760)  评论(0)    收藏  举报