第80部分- Linux x86 64位汇编 使用文件

第80部分- Linux x86 64位汇编 使用文件

我们知道C或者C++进行程序设计有函数fopen/read/write。汇编中如何呢?

汇编语言程序中处理数据文件时必须使用特定的顺序。通过Linux系统调用执行。

打开

先来按下open系统调用如下:

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

通过arch/x86/entry/syscalls/syscall_64.tbl中查看:

2       common  open                    __x64_sys_open

系统调用号是2.

打开模式如下:

例如创建文件并且打开用于读写访问:

可以使用$0102

新数据文件追加到已有的文件,可以使用:

$02002

模式可以入下:
#define S_IRWXU 00700     文件所有者可读可写可执行

#define S_IRUSR 00400     文件所有者可读

#define S_IWUSR 00200     文件所有者可写

#define S_IXUSR 00100     文件所有者可执行

 

#define S_IRWXG 00070     文件用户组可写可读可执行

#define S_IRGRP 00040     文件用户组可读

#define S_IWGRP 00020     文件用户组可写

#define S_IXGRP 00010     文件用户组可执行

#define S_IRWXO 00007     其他用户可写可读可执行

#define S_IROTH 00004     其他用户可读

#define S_IWOTH 00002     其他用户可写

#define S_IXOTH 00001     其他用户可执行

 

    1. read文件

读文件使用系统调用

ssize_t read(int fd, void *buf, size_t count);

系统调用号是0.

写入文件

写入文件使用系统调用write.

ssize_t write(int fd, const void *buf, size_t count);

系统调用号是1.

关闭文件

   int close(int fd);

系统调用号是3.

我们来看下示例如下。

写示例

.section .data

filename:
   .asciz "cpuid.txt"
output:
   .asciz "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
.section .bss
   .lcomm filehandle, 4
.section .text
.globl _start
_start:
   movl $0, %eax
   cpuid;//调用cpuid指令
   movl $output, %edi;//保存结果到字符串中
   movl %ebx, 28(%edi)
   movl %edx, 32(%edi)
   movl %ecx, 36(%edi)

   movl $2, %eax;//打开文件,系统调用open
   movq $filename, %rdi;//文件名
   movq $01101, %rsi;//打开模式,重新创建用于写。
   movq $0644, %rdx;//权限。
   
   syscall

   test %eax, %eax;//测试返回值
   js badfile
   movl %eax, filehandle;//否则返回保存eax文件句柄到filehandle

   movl $1, %eax;//进行写
   movq filehandle, %rdi;//参数句柄
   movq $output, %rsi;//参数字符串
   movq $42, %rdx;//参数字符串数量
   syscall
   test %eax, %eax
   js badfile

   movq $3, %rax;//关闭
   movq filehandle, %rdi;//对应的句柄
   syscall

badfile:
   movq %rax, %rbx
   movq $60, %rax
   syscall;//退出

as -g -o cpuidfile.o cpuidfile.s

ld -o cpuidfile cpuidfile.o

然后执行,

./cpuidfile可以发现执行成功。

 

读写示例

读后写入文件的示例

.section .bss
   .lcomm buffer, 10
   .lcomm filehandle, 4
.section .text
.globl _start
_start:
   nop
   movq %rsp, %rbp;//赋值rsp给rbp。
   movl $2, %eax;//打开文件open系统调用
   movq 16(%rbp), %rdi;//使用输入的参数为文件名字
   movq $00, %rsi;//flag为只读
   movq $0444, %rdx;//权限为只读
   syscall
   test %eax, %eax
   js badfile
   movl %eax, filehandle;//保存文件句柄,给read/write的系统调用使用

read_loop:
   movl $0, %eax
   movq filehandle, %rdi;//文件句柄
   movq $buffer, %rsi
   movq $10, %rdx;//每次10个
   syscall
   test %eax, %eax
   jz done;//读完跳出
   js done
   movl %eax, %edx

   movl $1, %eax;//写入系统调用
   movq $1, %rdi;//写到stdout
   movq $buffer, %rsi;//字符串
   syscall
   test %eax, %eax
   js badfile
   jmp read_loop

done:
   movl $3, %eax
   movq filehandle, %rdi
   syscall

badfile:
   movl %eax, %ebx
   movl $60, %eax
   syscall

as -g -o readwrite.o readwrite.s

ld -o readwrite readwrite.o

这里需要有个参数,就是一个文件名字。

将文件中的内容独处后放入到缓存中,然后将将缓存中写到stdout中。每次10个字节,使用更大块的长度可以减少read调用次数提高性能。

 

读后处理写入示例

相比上一个示例,这个示例增加数据处理的步骤。从文件读取数据,然后处理数据,最后把数据写入到另一个文件中。

.section .bss
   .lcomm buffer, 10
   .lcomm infilehandle, 8
   .lcomm outfilehandle, 8
   .lcomm size, 4
.section .text
.globl _start
_start:
   # open input file, specified by the first command line param
   movl $2, %eax;//open系统调用
   movq 16(%rsp), %rdi;//第一个参数,程序运行后栈指向的分别是参数数量/程序名字
   movq $00, %rsi;//只读
   movq $0444, %rdx;//权限
   syscall
   test %rax, %rax
   js badfile
   movq %rax, infilehandle;//保存输入文件的句柄

   movl $2, %eax;// open系统调用,打开另一个文件
   movq 24(%rsp), %rdi;// 第二个参数
   movq $01101, %rsi;//创建新文件,模式是写,
   movq $0644, %rdx;//权限
   syscall
   test %rax, %rax;//出现负数则跳转
   js badfile
   movq %rax, outfilehandle;//保存输出文件句柄

   # 从输入文件句柄中读取
read_loop:
   movl $0, %eax;// read系统调用
   movq infilehandle, %rdi
   movq $buffer, %rsi
   movq $10, %rdx;//每次读取10个字节
   syscall
   test %rax, %rax
   jz done
   js badfile
   movl %eax, size

   movq $buffer,%rdi;//字符串参数指针
   movq size,%rsi;// 第二个参数,已读出的字节数量。
   call convert;//调用convert函数

   # 将转换后的数据存放 output file
   movl $1, %eax ;// write系统调用
   movq outfilehandle, %rdi
   movq $buffer,%rsi
   syscall
   test %rax,%rax
   js badfile
   jmp read_loop

done:;//读取完毕后跳转到done处
   movl $3,%eax
   movq outfilehandle,%rdi
   syscall;//关闭输出文件句柄

   movl $3,%eax
   movq infilehandle,%rdi
   syscall;//关闭输入文件句柄

badfile:
   movl %eax,%ebx
   movl $60,%eax
   syscall

.type convert,@function
convert:
   movq %rsi,%rcx;//第二个参数是字符数量,赋值为rcx.
   movq %rdi,%rsi;//第二个参数是rdi指向源字符串的内存位置,要赋值给rsi

convert_loop:
   lodsb;//加载字符串字节到al寄存器,rsi指向源字符串的内存位置
   cmpb $0x61,%al;//是否小于0x61,即97,小于则跳过
   jl skip
   cmpb $0x7a,%al;//是否大于于0x7a,即122,大于也跳过
   jg skip
   sub $0x20,%al;//改成小写
skip:
   stosb;//重新加载al到rdi的字符串,就是源字符串地址。
   loop convert_loop
   ret

as -g -o readchange.o readchange.s

ld -o readchange readchange.o

可以执行如下

#readchange readchange.s out.txt

会将readchange.s文件中的内容转为大写并保存到了Out.txt文件中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值