gas 多文件组织

gas多文件工程

摘自:Programming from Groundup   Chapter 6

主要目的是了解如何组织多文件工程(形式)

 

 

文件record-def.s:

.equ RECORD_FIRSTNAME, 0

.equ RECORD_LASTNAME, 40

.equ RECORD_ADDRESS, 80

.equ RECORD_AGE, 320

.equ RECORD_SIZE, 324

 

文件linux.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_BRK, 45

#System Call Interrupt Number

.equ LINUX_SYSCALL, 0x80

#Standard File Descriptors

.equ STDIN, 0

.equ STDOUT, 1

.equ STDERR, 2

#Common Status Codes

.equ END_OF_FILE, 0

 

第一个程序Writing Records

文件:write-record.s

.include "linux.s"

.include "record-def.s"

#PURPOSE: This function writes a record to

# the given file descriptor

#

#INPUT: The file descriptor and a buffer

#

#OUTPUT: This function produces a status code

#

#STACK LOCAL VARIABLES

.equ ST_WRITE_BUFFER, 8

.equ ST_FILEDES, 12

.section .text

.globl write_record

.type write_record, @function

write_record:

pushl %ebp

movl %esp, %ebp

pushl %ebx

movl $SYS_WRITE, %eax

movl ST_FILEDES(%ebp), %ebx

movl ST_WRITE_BUFFER(%ebp), %ecx

movl $RECORD_SIZE, %edx

int $LINUX_SYSCALL

#NOTE - %eax has the return value, which we will

# give back to our calling program

popl %ebx

movl %ebp, %esp

popl %ebp

ret

 

 

文件write-records.s

.include "linux.s"

.include "record-def.s"

.section .data

#Constant data of the records we want to write

#Each text data item is padded to the proper

#length with null (i.e. 0) bytes.

#.rept is used to pad each item. .rept tells

#the assembler to repeat the section between

#.rept and .endr the number of times specified.

#This is used in this program to add extra null

#characters at the end of each field to fill

#it up

record1:

.ascii "Fredrick\0"

.rept 31 #Padding to 40 bytes

.byte 0

.endr

.ascii "Bartlett\0"

.rept 31 #Padding to 40 bytes

.byte 0

.endr

.ascii "4242 S Prairie\nTulsa, OK 55555\0"

.rept 209 #Padding to 240 bytes

.byte 0

.endr

.long 45

record2:

.ascii "Marilyn\0"

.rept 32 #Padding to 40 bytes

.byte 0

.endr

.ascii "Taylor\0"

.rept 33 #Padding to 40 bytes

.byte 0

.endr

.ascii "2224 S Johannan St\nChicago, IL 12345\0"

.rept 203 #Padding to 240 bytes

.byte 0

.endr

.long 29

record3:

.ascii "Derrick\0"

.rept 32 #Padding to 40 bytes

.byte 0

.endr

.ascii "McIntire\0"

.rept 31 #Padding to 40 bytes

.byte 0

.endr

.ascii "500 W Oakland\nSan Diego, CA 54321\0"

.rept 206 #Padding to 240 bytes

.byte 0

.endr

.long 36

#This is the name of the file we will write to

file_name:

.ascii "test.dat\0"

.equ ST_FILE_DESCRIPTOR, -4

.globl _start

_start:

#Copy the stack pointer to %ebp

movl %esp, %ebp

#Allocate space to hold the file descriptor

subl $4, %esp

#Open the file

movl $SYS_OPEN, %eax

movl $file_name, %ebx

movl $0101, %ecx #This says to create if it

#doesn’t exist, and open for

#writing

movl $0666, %edx

int $LINUX_SYSCALL

#Store the file descriptor away

movl %eax, ST_FILE_DESCRIPTOR(%ebp)

#Write the first record

pushl ST_FILE_DESCRIPTOR(%ebp)

pushl $record1

call write_record

addl $8, %esp

#Write the second record

pushl ST_FILE_DESCRIPTOR(%ebp)

pushl $record2

call write_record

addl $8, %esp

#Write the third record

pushl ST_FILE_DESCRIPTOR(%ebp)

pushl $record3

call write_record

addl $8, %esp

#Close the file descriptor

movl $SYS_CLOSE, %eax

movl ST_FILE_DESCRIPTOR(%ebp), %ebx

int $LINUX_SYSCALL

#Exit the program

movl $SYS_EXIT, %eax

movl $0, %ebx

int $LINUX_SYSCALL

 

To build the application, run the commands:

as write-records.s -o write-record.o

as write-record.s -o write-record.o

ld write-record.o write-records.o -o write-records

 

 

第二个程序Reading Records

文件read-record.s

.include "record-def.s"

.include "linux.s"

#PURPOSE: This function reads a record from the file

# descriptor

#

#INPUT: The file descriptor and a buffer

#

#OUTPUT: This function writes the data to the buffer

# and returns a status code.

#

#STACK LOCAL VARIABLES

.equ ST_READ_BUFFER, 8

.equ ST_FILEDES, 12

.section .text

.globl read_record

.type read_record, @function

read_record:

pushl %ebp

movl %esp, %ebp

pushl %ebx

movl ST_FILEDES(%ebp), %ebx

movl ST_READ_BUFFER(%ebp), %ecx

movl $RECORD_SIZE, %edx

movl $SYS_READ, %eax

int $LINUX_SYSCALL

#NOTE - %eax has the return value, which we will

# give back to our calling program

popl %ebx

movl %ebp, %esp

popl %ebp

ret

 

文件count-chars.s

#PURPOSE: Count the characters until a null byte is reached.

#

#INPUT: The address of the character string

#

#OUTPUT: Returns the count in %eax

#

#PROCESS:

# Registers used:

# %ecx - character count

# %al - current character

# %edx - current character address

.type count_chars, @function

.globl count_chars

#This is where our one parameter is on the stack

.equ ST_STRING_START_ADDRESS, 8

count_chars:

pushl %ebp

movl %esp, %ebp

#Counter starts at zero

movl $0, %ecx

#Starting address of data

movl ST_STRING_START_ADDRESS(%ebp), %edx

count_loop_begin:

#Grab the current character

movb (%edx), %al

#Is it null?

cmpb $0, %al

#If yes, we’re done

je count_loop_end

#Otherwise, increment the counter and the pointer

incl %ecx

incl %edx

#Go back to the beginning of the loop

jmp count_loop_begin

count_loop_end:

#We’re done. Move the count into %eax

#and return.

movl %ecx, %eax

popl %ebp

ret

 

文件write-newline.s

.include "linux.s"

.globl write_newline

.type write_newline, @function

.section .data

newline:

.ascii "\n"

.section .text

.equ ST_FILEDES, 8

write_newline:

pushl %ebp

movl %esp, %ebp

movl $SYS_WRITE, %eax

movl ST_FILEDES(%ebp), %ebx

movl $newline, %ecx

movl $1, %edx

int $LINUX_SYSCALL

movl %ebp, %esp

popl %ebp

ret

 

文件read-records.s

.include "linux.s"

.include "record-def.s"

.section .data

file_name:

.ascii "test.dat\0"

.section .bss

.lcomm record_buffer, RECORD_SIZE

.section .text

#Main program

.globl _start

_start:

#These are the locations on the stack where

#we will store the input and output descriptors

#(FYI - we could have used memory addresses in

#a .data section instead)

.equ ST_INPUT_DESCRIPTOR, -4

.equ ST_OUTPUT_DESCRIPTOR, -8

#Copy the stack pointer to %ebp

movl %esp, %ebp

#Allocate space to hold the file descriptors

subl $8, %esp

#Open the file

movl $SYS_OPEN, %eax

movl $file_name, %ebx

movl $0, %ecx #This says to open read-only

movl $0666, %edx

int $LINUX_SYSCALL

#Save file descriptor

movl %eax, ST_INPUT_DESCRIPTOR(%ebp)

#Even though it’s a constant, we are

#saving the output file descriptor in

#a local variable so that if we later

#decide that it isn’t always going to

#be STDOUT, we can change it easily.

movl $STDOUT, ST_OUTPUT_DESCRIPTOR(%ebp)

record_read_loop:

pushl ST_INPUT_DESCRIPTOR(%ebp)

pushl $record_buffer

call read_record

addl $8, %esp

#Returns the number of bytes read.

#If it isn’t the same number we

#requested, then it’s either an

#end-of-file, or an error, so we’re

#quitting

cmpl $RECORD_SIZE, %eax

jne finished_reading

#Otherwise, print out the first name

#but first, we must know it’s size

pushl $RECORD_FIRSTNAME + record_buffer

call count_chars

addl $4, %esp

movl %eax, %edx

movl ST_OUTPUT_DESCRIPTOR(%ebp), %ebx

movl $SYS_WRITE, %eax

movl $RECORD_FIRSTNAME + record_buffer, %ecx

int $LINUX_SYSCALL

pushl ST_OUTPUT_DESCRIPTOR(%ebp)

call write_newline

addl $4, %esp

jmp record_read_loop

finished_reading:

movl $SYS_EXIT, %eax

movl $0, %ebx

int $LINUX_SYSCALL

 

To build this program, we need to assemble all of the parts and link them together:

as read-record.s -o read-record.o

as count-chars.s -o count-chars.o

as write-newline.s -o write-newline.o

as read-records.s -o read-records.o

ld read-record.o count-chars.o write-newline.o \

read-records.o -o read-records

 

第三个程序Modifying the Records

文件add-year.s

.include "linux.s"

.include "record-def.s"

.section .data

input_file_name:

.ascii "test.dat\0"

output_file_name:

.ascii "testout.dat\0"

.section .bss

.lcomm record_buffer, RECORD_SIZE

#Stack offsets of local variables

.equ ST_INPUT_DESCRIPTOR, -4

.equ ST_OUTPUT_DESCRIPTOR, -8

.section .text

.globl _start

_start:

#Copy stack pointer and make room for local variables

movl %esp, %ebp

subl $8, %esp

#Open file for reading

movl $SYS_OPEN, %eax

movl $input_file_name, %ebx

movl $0, %ecx

movl $0666, %edx

int $LINUX_SYSCALL

movl %eax, ST_INPUT_DESCRIPTOR(%ebp)

#Open file for writing

movl $SYS_OPEN, %eax

movl $output_file_name, %ebx

movl $0101, %ecx

movl $0666, %edx

int $LINUX_SYSCALL

movl %eax, ST_OUTPUT_DESCRIPTOR(%ebp)

loop_begin:

pushl ST_INPUT_DESCRIPTOR(%ebp)

pushl $record_buffer

call read_record

addl $8, %esp

#Returns the number of bytes read.

#If it isn’t the same number we

#requested, then it’s either an

#end-of-file, or an error, so we’re

#quitting

cmpl $RECORD_SIZE, %eax

jne loop_end

#Increment the age

incl record_buffer + RECORD_AGE

#Write the record out

pushl ST_OUTPUT_DESCRIPTOR(%ebp)

pushl $record_buffer

call write_record

addl $8, %esp

jmp loop_begin

loop_end:

movl $SYS_EXIT, %eax

movl $0, %ebx

int $LINUX_SYSCALL

 

 

To build it, type the following4:

as add-year.s -o add-year.o

ld add-year.o read-record.o write-record.o -o add-year

你可能感兴趣的:(文件)