mips中的Sprintf
所以我尝试在MIPS中创建Sprintf。问题是,我不知道如何处理%d、%c等的所有情况 所以,即使我真的能认出%我怎么能认出下一个字符呢?我的意思是,我在3美元的登记册中有%。 李:3美元,“%” 但是,对于$d、%c、%b等,我没有足够的寄存器 我如何检查它们mips中的Sprintf,mips,printf,Mips,Printf,所以我尝试在MIPS中创建Sprintf。问题是,我不知道如何处理%d、%c等的所有情况 所以,即使我真的能认出%我怎么能认出下一个字符呢?我的意思是,我在3美元的登记册中有%。 李:3美元,“%” 但是,对于$d、%c、%b等,我没有足够的寄存器 我如何检查它们 ###################################################################### # spf-main.s # # This is the main function th
######################################################################
# spf-main.s
#
# This is the main function that tests the sprintf function
# The "data" segment is a static memory area where we can
# allocate and initialize memory for our program to use.
# This is separate from the stack or the heap, and the allocation
# cannot be changed once the program starts. The program can
# write data to this area, though.
.data
# Note that the directives in this section will not be
# translated into machine language. They are instructions
# to the assembler, linker, and loader to set aside (and
# initialize) space in the static memory area of the program.
# The labels work like pointers-- by the time the code is
# run, they will be replaced with appropriate addresses.
# For this program, we will allocate a buffer to hold the
# result of your sprintf function. The asciiz blocks will
# be initialized with null-terminated ASCII strings.
buffer: .space 20000 # 2000 bytes of empty space
# starting at address 'buffer'
format: .asciiz "string: %s, unsigned dec: %u, hex: 0x%x, char: %c, dec: %d, bin: %b, percent: %%\n"
# null-terminated string of
# ascii bytes. Note that the
# \n counts as one byte: a newline
# character.
str: .asciiz "thirty-nine" # null-terminated string at
# address 'str'
chrs: .asciiz " characters:\n" # null-terminated string at
# address 'chrs'
strpd: .asciiz "%d" # null-terminated string at
strpc: .asciiz "%c" # null-terminated string at
strpb: .asciiz "%b" # null-terminated string at
strpu: .asciiz "%u" # null-terminated string at
strpx: .asciiz "%x" # null-terminated string at
strpo: .asciiz "%o" # null-terminated string at
strps: .asciiz "%s" # null-terminated string at
strpp: .asciiz "%%" # null-terminated string at
strpi: .asciiz "%" # null-terminated string at
# The "text" of the program is the assembly code that will
# be run. This directive marks the beginning of our program's
# text segment.
.text
# The sprintf procedure (really just a block that starts with the
# label 'sprintf') will be declared later. This is like a function
# prototype in C.
.globl sprintf
# The special label called "__start" marks the start point
# of execution. Later, the "done" pseudo-instruction will make
# the program terminate properly.
main:
addi $sp,$sp,-36 # reserve stack space
# $v0 = sprintf(buffer, format, str, 255, 255, 111, -255, -255)
la $a0,buffer # arg 0 <- buffer
la $a1,format # arg 1 <- format
la $a2,str # arg 2 <- str
addi $a3,$0,255 # arg 3 <- 255
sw $a3,16($sp) # arg 4 <- 255
addi $t0,$0,111
sw $t0,20($sp) # arg 5 <- 111 ('o', as a character)
addi $t0,$0,-255
sw $t0,24($sp) # arg 6 <- -255
addi $t0,$0,255
sw $t0,28($sp) # arg 7 <- 255
sw $ra,32($sp) # save return address
jal sprintf # $v0 = sprintf(...)
# print the return value from sprintf using
# putint()
add $a0,$v0,$0 # $a0 <- $v0
jal putint # putint($a0)
## output the string 'chrs' then 'buffer' (which
## holds the output of sprintf)
li $v0, 4
la $a0, chrs
syscall
#puts chrs # output string chrs
li $v0, 4
la $a0, buffer
syscall
#puts buffer # output string buffer
addi $sp,$sp,36 # restore stack
li $v0, 10 # terminate program
syscall
# putint writes the number in $a0 to the console
# in decimal. It uses the special command
# putc to do the output.
# Note that putint, which is recursive, uses an abbreviated
# stack. putint was written very carefully to make sure it
# did not disturb the stack of any other functions. Fortunately,
# putint only calls itself and putc, so it is easy to prove
# that the optimization is safe. Still, we do not recommend
# taking shortcuts like the ones used here.
# HINT: You should read and understand the body of putint,
# because you will be doing some similar conversions
# in your own code.
putint: addi $sp,$sp,-8 # get 2 words of stack
sw $ra,0($sp) # store return address
# The number is printed as follows:
# It is successively divided by the base (10) and the
# reminders are printed in the reverse order they were found
# using recursion.
remu $t0,$a0,10 # $t0 <- $a0 % 10
addi $t0,$t0,'0' # $t0 += '0' ($t0 is now a digit character)
divu $a0,$a0,10 # $a0 /= 10
beqz $a0,onedig # if( $a0 != 0 ) {
sw $t0,4($sp) # save $t0 on our stack
jal putint # putint() (putint will deliberately use and modify $a0)
lw $t0,4($sp) # restore $t0
# }
onedig: move $a0, $t0
li $v0, 11
syscall # putc #$t0
#putc $t0 # output the digit character $t0
lw $ra,0($sp) # restore return address
addi $sp,$sp, 8 # restore stack
jr $ra # return
#sprintf!
#$a0 has the pointer to the buffer to be printed to
#$a1 has the pointer to the format string
#$a2 and $a3 have (possibly) the first two substitutions for the format string
#the rest are on the stack
#return the number of characters (ommitting the trailing '\0') put in the buffer
.text
sprintf:
addi $sp, $sp, -12
sw $ra, 8($sp)
sw $s1, 4($sp)
sw $s2, 0($sp)
li $a3, '%'
li $s0, 0 # len = 1
la $s1, ($a1) # s = str
test:
lb $s2, 0($s1) # c = *s
beqz $s2, done # if c == '\0', branch to "done"
# beq $s2, $a3, percent
addi $s0, $s0, 1 # len = len + 1
addi $s1, $s1, 1 # s = s + 1
j test
percent:
li $v0, 4 # print_string
la $a0, str
syscall
done:
# li $v0, 1 # syscall code: print_int
# move $a0, $s0
# syscall
li $v0, 11 # syscall code: print_char
li $a0, 10 # pass newline character
syscall
add $v0,$0, $s0
lw $ra, 8($sp)
lw $s1, 4($sp)
lw $s2, 0($sp)
addi $sp, $sp, 12
jr $ra
######################################################################
#spf main.s
#
#这是测试sprintf函数的主要函数
#“数据”段是一个静态内存区域,我们可以在其中
#为我们的程序分配并初始化内存。
#这与堆栈或堆以及分配是分开的
#程序启动后无法更改。该程序可以
#不过,请将数据写入此区域。
.数据
#请注意,本节中的指令不适用
#翻译成机器语言。它们是指令
#到要搁置的汇编器、链接器和加载程序(以及
#初始化)程序静态内存区域中的空间。
#标签的工作方式类似于指针——在编写代码时
#运行时,它们将被相应的地址替换。
#对于这个程序,我们将分配一个缓冲区来保存
#sprintf函数的结果。asciiz区块将
#可以使用以null结尾的ASCII字符串初始化。
缓冲区:.空间20000#2000字节的空白空间
#从地址“缓冲区”开始
格式:.asciiz“字符串:%s,未签名的dec:%u,十六进制:0x%x,字符:%c,dec:%d,bin:%b,百分比:%%\n”
#以null结尾的字符串
#ascii字节。请注意
#\n计为一个字节:换行符
#性格。
str:.asciiz“三十九”#以null结尾的字符串位于
#地址'str'
chrs:.asciiz“字符:\n”#以null结尾的字符串位于
#地址“chrs”
strpd:.asciiz“%d”#以null结尾的字符串位于
strpc:.asciiz“%c”#以null结尾的字符串位于
strpb:.asciiz“%b”#以null结尾的字符串位于
strpu:.asciiz“%u”#以null结尾的字符串位于
strpx:.asciiz“%x”#以null结尾的字符串位于
strpo:.asciiz“%o”#以null结尾的字符串位于
strps:.asciiz“%s”#以null结尾的字符串位于
strpp:.asciiz“%%”#以null结尾的字符串位于
strpi:.asciiz“%”#以null结尾的字符串位于
#程序的“文本”是将
#被运行。该指令标志着我们的计划的开始
#文本段。
.文本
#sprintf过程(实际上只是一个以
#稍后将声明标签“sprintf”)。这就像一个函数
#原型用C。
环球斯普林特酒店
#名为“开始”的特殊标签标记了开始点
#执行的方式。稍后,“done”伪指令将生成
#程序正常终止。
主要内容:
addi$sp,$sp,-36#保留堆栈空间
#$v0=sprintf(缓冲区,格式,str,255,255,111,-255,-255)
la$a0,buffer#arg 0您需要一个循环来检查sprintf
函数中的下一个字符。此循环应扫描下一个字符,将其与要使用的可用字符列表进行比较,然后分支到必要的函数,这包括返回循环,以防您得到%%
,您可以使用C语言获取sprintf实现,并使用MIPS编译器将其机器翻译为MIPS程序集,以便查看它是如何完成的。