`

assembly - record in file

 
阅读更多

maintain record in file using assembly,

 

------

table & record

 

design a simple table which has several fields with fixed-length,

the records are saved in file permanently,


------

operations on records

 

insert:

    add a record to end of file,

select:

    get a record by line number, and print it,


------

code

 

 

files list:

* record_insert.s

      insert a new record

* record_select.s

      select & print a record by line number(start from 0)

* record_const.s

      record relative constants,

* linux_const.s

      linux relative constants,

* string_util.s

string util functions,


 

record_insert.s:

 

# record operations - insert

.include "record_const.s"
.include "linux_const.s"
.include "string_util.s"

.section .data
.equ ST_ARGC, 4
.equ ST_ARGV_0, 8	# program path
.equ ST_ARGV_1, 12	# output file path
.equ ST_ARGV_2, 16	# field - id
.equ ST_ARGV_3, 20	# field - name
.equ ST_ARGV_4, 24	# field - age
.equ ST_ARGV_5, 28	# field - email
.equ ST_ARGV_6, 32	# field - address
.equ ST_RESERVE_SIZE, 4
.equ ST_FD_OUT, -4

.section .bss
.equ BUF_SIZE, RECORD_SIZE_FULL		# last byte is '\n'
.lcomm BUF_DATA, BUF_SIZE

.section .text
.globl _start

_start:
pushl %ebp
movl %esp, %ebp
subl $ST_RESERVE_SIZE, %esp	# reserve stack

prepare_buf:
pushl ST_ARGV_2(%ebp)		# id
call str_to_int
addl $4, %esp
movl $BUF_DATA, %ebx
movl %eax, RECORD_ID(%ebx)
pushl $RECORD_SIZE_NAME		# name
movl $BUF_DATA+RECORD_NAME, %ebx
pushl %ebx
pushl ST_ARGV_3(%ebp)
call str_copy
addl $12, %esp
pushl ST_ARGV_4(%ebp)		# age
call str_to_int
addl $4, %esp
movl $BUF_DATA, %ebx
movl %eax, RECORD_AGE(%ebx)
pushl $RECORD_SIZE_EMAIL	# email
movl $BUF_DATA+RECORD_EMAIL, %ebx
pushl %ebx
pushl ST_ARGV_5(%ebp)
call str_copy
addl $12, %esp
pushl $RECORD_SIZE_ADDRESS	# address
movl $BUF_DATA+RECORD_ADDRESS, %ebx
pushl %ebx
pushl ST_ARGV_6(%ebp)
call str_copy
addl $12, %esp

open_file:
open_file_append:
movl $SYS_OPEN, %eax
movl ST_ARGV_1(%ebp), %ebx
movl $MODE_WRONLY_APPEND, %ecx
movl $0644, %edx
int $LINUX_SYSCALL
movl %eax, ST_FD_OUT(%ebp)
cmpl $0, %eax
jg write_record

open_file_create:		# output file not exists, close it first, then create it
movl $SYS_CLOSE, %eax
movl ST_FD_OUT(%ebp), %ebx
int $LINUX_SYSCALL
movl $SYS_OPEN, %eax
movl ST_ARGV_1(%ebp), %ebx
movl $MODE_WRONLY_TRUNC, %ecx
int $LINUX_SYSCALL
movl %eax, ST_FD_OUT(%ebp)
cmpl $0, %eax
jl exit				# can't open/create output file, exit

write_record:
movl $BUF_DATA, %eax
addl $BUF_SIZE, %eax
movb $END_OF_LINE, -1(%eax)	# prepare last char of record
movl $SYS_WRITE, %eax
movl ST_FD_OUT(%ebp), %ebx
movl $BUF_DATA, %ecx
movl $BUF_SIZE, %edx
int $LINUX_SYSCALL

close_file:
movl $SYS_CLOSE, %eax
movl ST_FD_OUT(%ebp), %ebx
int $LINUX_SYSCALL

exit:
movl %ebp, %esp
popl %ebp
movl $SYS_EXIT, %eax
int $LINUX_SYSCALL

 

record_select.s:

 

# record operations - select & print record by line number

.include "record_const.s"
.include "linux_const.s"
.include "string_util.s"

.section .data
.equ ST_ARGC, 4
.equ ST_ARGV_0, 8	# program path
.equ ST_ARGV_1, 12	# input file path
.equ ST_ARGV_2, 16	# field - line number string, start from 0
.equ ST_RESERVE_SIZE, 4
.equ ST_LINE_NUM, -4	# converted line number
.LC0:
	.string "%10s:\t%s\n"
.LC1:
	.string "%10s:\t%d\n"
.LC2:
	.string "line %d not exists\n"

.section .bss
.equ BUF_SIZE, RECORD_SIZE_FULL		# last byte is '\n'
.lcomm BUF_DATA, BUF_SIZE

.section .text
.globl _start

_start:
pushl %ebp
movl %esp, %ebp
subl $ST_RESERVE_SIZE, %esp	# reserve stack
pushl ST_ARGV_2(%ebp)
call str_to_int
addl $4, %esp
movl %eax, ST_LINE_NUM(%ebp)
imull $RECORD_SIZE_FULL, %eax
pushl %eax		# record offset, TODO figure this according to command-line param
pushl ST_ARGV_1(%ebp)
call load_record
addl $8, %esp
cmpl $0, %eax
je line_not_exists	# specified line not exists
pushl $BUF_DATA
call print_record
addl $4, %esp
jmp exit

line_not_exists:
pushl ST_LINE_NUM(%ebp)
pushl $.LC2
call printf
addl $8, %esp

exit:
movl %ebp, %esp
popl %ebp
movl $SYS_EXIT, %eax
int $LINUX_SYSCALL

# function - load a record into buffer
# params
#	@param 0: file path
#	@param 1: record offset(byte) in file
# storage
# 
# return: actual read size(byte), stored in %eax
# 
.type load_record, @function
load_record:
.equ ST_LOADRECORD_PARAM_FILE_PATH, 8
.equ ST_LOADRECORD_PARAM_OFFSET, 12
.equ ST_LOADRECORD_RESERVE_SIZE, 8
.equ ST_LOADRECORD_FD_IN, -4
.equ ST_LOADRECORD_ACTUAL_READ_SIZE, -8
pushl %ebp
movl %esp, %ebp
subl $ST_LOADRECORD_RESERVE_SIZE, %esp	# reserve stack
load_record_open_file:
movl $SYS_OPEN, %eax
movl ST_LOADRECORD_PARAM_FILE_PATH(%ebp), %ebx
movl $MODE_RDONLY, %ecx
movl $0644, %edx
int $LINUX_SYSCALL
movl %eax, ST_LOADRECORD_FD_IN(%ebp)
load_record_seek:
movl $SYS_SEEK, %eax
movl ST_LOADRECORD_FD_IN(%ebp), %ebx
movl ST_LOADRECORD_PARAM_OFFSET(%ebp), %ecx
movl $0, %edx
int $LINUX_SYSCALL
load_record_read:
movl $SYS_READ, %eax
movl ST_LOADRECORD_FD_IN(%ebp), %ebx
movl $BUF_DATA, %ecx
movl $BUF_SIZE, %edx
int $LINUX_SYSCALL
movl %eax, ST_LOADRECORD_ACTUAL_READ_SIZE(%ebp)
load_record_close_file:
movl $SYS_CLOSE, %eax
movl ST_LOADRECORD_FD_IN(%ebp), %ebx
int $LINUX_SYSCALL

load_record_end:
movl ST_LOADRECORD_ACTUAL_READ_SIZE(%ebp), %eax
movl %ebp, %esp
popl %ebp
ret

# function - print record to stdout
# params
#	@param 0: buf_data, start address of buffer
# storage
# 
# return: 
# 
.type print_record, @function
.equ ST_PRINTRECORD_PARAM_BUF_DATA, 8
.equ ST_PRINTRECORD_RESERVE_SIZE, 12
.equ ST_PRINTRECORD_FIELD, -4		# printf param - string -> field address in buffer, int -> value
.equ ST_PRINTRECORD_TITLE, -8		# printf param - field title
.equ ST_PRINTRECORD_STRING, -12	# printf param - string
print_record:
pushl %ebp
movl %esp, %ebp
subl $ST_PRINTRECORD_RESERVE_SIZE, %esp	# reserve stack
movl ST_PRINTRECORD_PARAM_BUF_DATA(%ebp), %edx		# print id
movl RECORD_ID(%edx), %ecx
movl %ecx, ST_PRINTRECORD_FIELD(%ebp)
movl $RECORD_FIELD_TITLE_ID, ST_PRINTRECORD_TITLE(%ebp)
movl $.LC1, ST_PRINTRECORD_STRING(%ebp)
call printf
movl ST_PRINTRECORD_PARAM_BUF_DATA(%ebp), %edx		# print name
addl $RECORD_NAME, %edx
movl %edx, ST_PRINTRECORD_FIELD(%ebp)
movl $RECORD_FIELD_TITLE_NAME, ST_PRINTRECORD_TITLE(%ebp)
movl $.LC0, ST_PRINTRECORD_STRING(%ebp)
call printf
movl ST_PRINTRECORD_PARAM_BUF_DATA(%ebp), %edx		# print age
movl RECORD_AGE(%edx), %ecx
movl %ecx, ST_PRINTRECORD_FIELD(%ebp)
movl $RECORD_FIELD_TITLE_AGE, ST_PRINTRECORD_TITLE(%ebp)
movl $.LC1, ST_PRINTRECORD_STRING(%ebp)
call printf
movl ST_PRINTRECORD_PARAM_BUF_DATA(%ebp), %edx		# print email
addl $RECORD_EMAIL, %edx
movl %edx, ST_PRINTRECORD_FIELD(%ebp)
movl $RECORD_FIELD_TITLE_EMAIL, ST_PRINTRECORD_TITLE(%ebp)
movl $.LC0, ST_PRINTRECORD_STRING(%ebp)
call printf
movl ST_PRINTRECORD_PARAM_BUF_DATA(%ebp), %edx		# print address
addl $RECORD_ADDRESS, %edx
movl %edx, ST_PRINTRECORD_FIELD(%ebp)
movl $RECORD_FIELD_TITLE_ADDRESS, ST_PRINTRECORD_TITLE(%ebp)
movl $.LC0, ST_PRINTRECORD_STRING(%ebp)
call printf

print_record_end:
movl %ebp, %esp
popl %ebp
ret
 

record_const.s:

 

# record constants, include field size/offset/.. ,
# 
# end of each string field is 0, which takes 1 byte,
# each int field is 4 byte,
# end of each record is '\n', which takes 1 byte,

.equ RECORD_SIZE_ID, 4
.equ RECORD_SIZE_NAME, 40
.equ RECORD_SIZE_AGE, 4
.equ RECORD_SIZE_EMAIL, 60
.equ RECORD_SIZE_ADDRESS, 252
.equ RECORD_SIZE_EXTRA, 1	# extra size, 1 byte for a new line char '\n' at the end of record,
# total size of record, = sum of all fields' size
.equ RECORD_SIZE, RECORD_SIZE_ID+RECORD_SIZE_NAME+RECORD_SIZE_AGE+RECORD_SIZE_EMAIL+RECORD_SIZE_ADDRESS
.equ RECORD_SIZE_FULL, RECORD_SIZE+RECORD_SIZE_EXTRA
# offset address of record fields, = previous_field_offset + previous_field_size, of cause the first field has offset = 0
.equ RECORD_ID, 0
.equ RECORD_NAME, RECORD_ID+RECORD_SIZE_ID
.equ RECORD_AGE, RECORD_NAME+RECORD_SIZE_NAME
.equ RECORD_EMAIL, RECORD_AGE+RECORD_SIZE_AGE
.equ RECORD_ADDRESS, RECORD_EMAIL+RECORD_SIZE_EMAIL
# record filed title
.section .data
RECORD_FIELD_TITLE_ID:
	.string "id"
RECORD_FIELD_TITLE_NAME:
	.string "name"
RECORD_FIELD_TITLE_AGE:
	.string "age"
RECORD_FIELD_TITLE_EMAIL:
	.string "email"
RECORD_FIELD_TITLE_ADDRESS:
	.string "address"
 

linux_const.s:

 

#Common Linux Definitions
#System Call Numbers
.equ SYS_EXIT, 1
.equ SYS_READ, 3
.equ SYS_WRITE, 4
.equ SYS_OPEN, 5
.equ SYS_CLOSE, 6
.equ SYS_SEEK, 19
.equ SYS_BRK, 45
#System Call Interrupt Number
.equ LINUX_SYSCALL, 0x80
# file open mode
.equ MODE_RDONLY, 0
.equ MODE_WRONLY, 0101
.equ MODE_WRONLY_TRUNC, 03101
.equ MODE_WRONLY_APPEND, 02001
#Standard File Descriptors
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2
#Common Status Codes
.equ END_OF_FILE, 0
# string
.equ END_OF_STRING, 0
.equ END_OF_LINE, '\n'
 

string_util.s:

 

# string utils

.section .text
# functionn - convert string to int
# params
#       @param 0: start address of string
# storage
#       %eax:   result
#       %ebx:   number of each char
#       %ecx:   start address of string
#       %edi:   index
# 
# return: converted int value, stored in %eax
# 
.type str_to_int, @function
.equ ST_STRTOINT_PARAM_STR, 8
str_to_int:
pushl %ebp
movl %esp, %ebp
movl $0, %eax
movl ST_STRTOINT_PARAM_STR(%ebp), %ecx
movl $0, %edi

str_to_int_loop:
movzbl (%ecx, %edi, 1), %ebx
cmpl $END_OF_STRING, %ebx
je str_to_int_end
subl $0x30, %ebx
imull $0xa, %eax
addl %ebx, %eax
incl %edi
jmp str_to_int_loop

str_to_int_end:
movl %ebp, %esp
popl %ebp
ret

# function - copy a string, from one location to another in memory
# params
#       @param 0: start address of source str
#       @param 1: start address of target str
#       @param 2: max size(byte) limit of str(include '\0'),
# storage
#       %eax: start address of source str
#       %ebx: start address of target str
#       %cl:  current char
#       %edx: str max size limit
#       %edi: index
# 
# return: actual size(byte) of copyed str, stored in %eax
# 
.type str_copy, @function
str_copy:
.equ ST_READPARAMSTR_PARAM_SOURCE, 8
.equ ST_READPARAMSTR_PARAM_TARGET, 12
.equ ST_READPARAMSTR_PARAM_MAX_SIZE, 16
pushl %ebp
movl %esp, %ebp
movl ST_READPARAMSTR_PARAM_SOURCE(%ebp), %eax
movl ST_READPARAMSTR_PARAM_TARGET(%ebp), %ebx
movl ST_READPARAMSTR_PARAM_MAX_SIZE(%ebp), %edx
decl %edx
movl $0, %edi

str_copy_loop:
cmpl %edx, %edi
jl read_param_char
read_param_limit_reach:                 # reach field size limit
movb $END_OF_STRING, (%ebx,%edi,1)
incl %edi
jmp str_copy_end
read_param_char:                        # read a char
movzbl (%eax,%edi,1), %ecx
movb %cl, (%ebx,%edi,1)
incl %edi
cmpb $END_OF_STRING, %cl
je str_copy_end
jmp str_copy_loop

str_copy_end:
movl %edi, %eax
movl %ebp, %esp
popl %ebp
ret

 

 

------

how to use

 

environment:

      hardware: x86 architecture,

      software: linux(ubuntu 10.04 LTS), gcc

 

compile:

      as -gstabs record_insert.s -o a; ld a -o insert.out -lc -dynamic-linker /lib/ld-linux.so.2

      as -gstabs record_select.s -o a; ld a -o select.out -lc -dynamic-linker /lib/ld-linux.so.2

 

insert:

      ./insert.out /tmp/a.txt 4 monica 26 friends_monica@gmail.com "USA NK, central park"

 

select:

      ./select.out /tmp/a.txt 0

 

------


分享到:
评论

相关推荐

    ehlib_vcl_src_9_3.26

    Allows create and fill data in design-time and save data in dfm file of the Form. Allows keep record in the manner of trees. Each record can have record elements-branches and itself be an ...

    EhLib 9.1.024

    Allows create and fill data in design-time and save data in dfm file of the Form. Allows keep record in the manner of trees. Each record can have record elements-branches and itself be an ...

    Quartus II 5.1文件后缀

    15. **.qar** - Quartus Assembly File:这是一种装配文件,用于保存装配后的设计数据。 16. **.mif** - Memory Initialization File:这是一种内存初始化文件,用于初始化 ROM 或 RAM 等存储器的初始值。 17. **....

    EhLib 8.0 Build 8.0.023 Pro Edition FullSource for D7-XE8

    Allows create and fill data in design-time and save data in dfm file of the Form. Allows keep record in the manner of trees. Each record can have record elements-branches and itself be an ...

    EhLib 6.3 Build 6.3.176 Russian version. Full source included.

    Allows create and fill data in design-time and save data in dfm file of the Form. Allows keep record in the manner of trees. Each record can have record elements-branches and itself be an ...

    EhLib5.0.13 最新的ehlib源码

    Allows create and fill data in design-time and save data in dfm file of the Form. Allows keep record in the manner of trees. Each record can have record elements-branches and itself be an ...

    hex.bin elf axf文件区别

    '01' End of File Record: 用来标识文件结束,放在文件的最后,标识 HEX 文件的结尾 '04' Extended Linear Address Record: 用来标识扩展线性地址的记录 '02' Extended Segment Address Record: 用来标识扩展段地址...

    k7 SRIO参考例程

    - Assembly Information CAR (offset 0xC) - ExtendedFeaturesPtr portion - Processing Element Features CAR (offset 0x10) - Switch Port Information CAR (offset 0x14) - Destination Operations CAR ...

    Android代码-Android学习

    AndroidWaveRecorder: record pcm raw audio and put into a wave file in Android using AudioRecord classAndroidPCMRecorder: record pcm raw audio in Android using AudioRecord classCalendarOps: Android ...

    2021-2022计算机二级等级考试试题及答案No.17518.docx

    It provides six built-in objects: Response, Request, Server, Application, Session, and Cookie. These objects facilitate communication between the server and client, handle HTTP requests and responses...

    Cadence&Allegro中文教程

    - 录制:选择`File-Script`命令,输入文件名`colors`并点击`Record`开始录制。 - 设置显示选项:使用`Color/Visibility`命令进行显示控制,如全关(`Global Visibility`设置为`All Invisible`)。 - 设置显示对象:...

    汇编语言编程常见错误中英文对照(网上找的)

    stopping assembly** (错误数量超过100个;停止汇编): 当编译过程中出现的错误数量达到100个时,汇编器会自动停止继续编译,避免产生无用的输出。 - **invalid numerical command-line argument** (无效的数值型...

    汇编错误提示大全

    stopping assembly** - 错误数超过100,停止汇编,表明程序中有太多的错误,汇编器无法继续处理。 11. **invalid numerical command-line argument** - 无效的数值型命令行参数,这通常是因为用户输入了非法的...

    nasm-2.07汇编编译器

    NASM可以生成COFF(Microsoft Common Object File Format)、ELF(Executable and Linkable Format,常见于Linux系统)、O coff、a.out(旧式Unix系统)、Win32/64 PE格式的可执行文件,以及Intel HEX和Motorola S-...

    中英文对照—masm编译时错误性息提示 汇编语言

    29. non-benign record redefinition 没有利于记录的定义 该错误提示表示MASM编译器发现了没有利于记录的定义,可能是由于编程错误或编译器配置错误等原因所致。 30. syntax error 语法错误 该错误提示表示MASM...

    汇编语言常见错误信息中文注解

    stopping assembly**:错误数超过100,停止汇编,表示程序中有大量的错误,编译器不再继续处理。 11. **invalid numerical command-line argument**:无效的数字命令行参数,可能是数值格式错误。 12. **too many...

    FAT12引导程序:FAT12引导程序(软盘2880K)

    标题中的"FAT12引导程序"指的是用于启动MS-DOS或早期Windows系统中使用的文件分配表(File Allocation Table)版本12的引导加载器。在2880KB的软盘上,FAT12是标准的文件系统,用于管理和组织磁盘上的数据。 FAT12...

Global site tag (gtag.js) - Google Analytics