mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 16:36:21 +00:00
626 lines
14 KiB
ArmAsm
626 lines
14 KiB
ArmAsm
#
|
|
# linux_logo in i386 assembly language
|
|
# based on the code from ll_asm-0.36
|
|
#
|
|
# By Vince Weaver <vince _at_ deater.net>
|
|
#
|
|
# Modified to remove non-deterministic system calls
|
|
# And to avoid reading from /proc
|
|
#
|
|
|
|
.include "logo.include"
|
|
|
|
# offsets into the results returned by the uname syscall
|
|
.equ U_SYSNAME,0
|
|
.equ U_NODENAME,65
|
|
.equ U_RELEASE,65*2
|
|
.equ U_VERSION,(65*3)
|
|
.equ U_MACHINE,(65*4)
|
|
.equ U_DOMAINNAME,65*5
|
|
|
|
# offset into the results returned by the sysinfo syscall
|
|
.equ S_TOTALRAM,16
|
|
|
|
# Sycscalls
|
|
.equ SYSCALL_EXIT, 1
|
|
.equ SYSCALL_WRITE, 4
|
|
|
|
#
|
|
.equ STDIN,0
|
|
.equ STDOUT,1
|
|
.equ STDERR,2
|
|
|
|
.globl _start
|
|
_start:
|
|
#=========================
|
|
# PRINT LOGO
|
|
#=========================
|
|
|
|
# LZSS decompression algorithm implementation
|
|
# by Stephan Walter 2002, based on LZSS.C by Haruhiko Okumura 1989
|
|
# optimized some more by Vince Weaver
|
|
|
|
# we used to fill the buffer with FREQUENT_CHAR
|
|
# but, that only gains us one byte of space in the lzss image.
|
|
# the lzss algorithm does automatic RLE... pretty clever
|
|
# so we compress with NUL as FREQUENT_CHAR and it is pre-done for us
|
|
|
|
mov $(N-F), %bp # R
|
|
|
|
mov $logo, %esi # %esi points to logo (for lodsb)
|
|
|
|
mov $out_buffer, %edi # point to out_buffer
|
|
push %edi # save this value for later
|
|
|
|
decompression_loop:
|
|
lodsb # load in a byte
|
|
|
|
mov $0xff, %bh # re-load top as a hackish 8-bit counter
|
|
mov %al, %bl # move in the flags
|
|
|
|
test_flags:
|
|
cmp $logo_end, %esi # have we reached the end?
|
|
je done_logo # if so, exit
|
|
|
|
shr $1, %ebx # shift bottom bit into carry flag
|
|
jc discrete_char # if set, we jump to discrete char
|
|
|
|
offset_length:
|
|
lodsw # get match_length and match_position
|
|
mov %eax,%edx # copy to edx
|
|
# no need to mask dx, as we do it
|
|
# by default in output_loop
|
|
|
|
shr $(P_BITS),%eax
|
|
add $(THRESHOLD+1),%al
|
|
mov %al,%cl # cl = (ax >> P_BITS) + THRESHOLD + 1
|
|
# (=match_length)
|
|
|
|
output_loop:
|
|
and $POSITION_MASK,%dh # mask it
|
|
mov text_buf(%edx), %al # load byte from text_buf[]
|
|
inc %edx # advance pointer in text_buf
|
|
store_byte:
|
|
stosb # store it
|
|
|
|
mov %al, text_buf(%ebp) # store also to text_buf[r]
|
|
inc %ebp # r++
|
|
and $(N-1), %bp # mask r
|
|
|
|
loop output_loop # repeat until k>j
|
|
|
|
or %bh,%bh # if 0 we shifted through 8 and must
|
|
jnz test_flags # re-load flags
|
|
|
|
jmp decompression_loop
|
|
|
|
discrete_char:
|
|
lodsb # load a byte
|
|
inc %ecx # we set ecx to one so byte
|
|
# will be output once
|
|
# (how do we know ecx is zero?)
|
|
|
|
jmp store_byte # and cleverly store it
|
|
|
|
|
|
# end of LZSS code
|
|
|
|
done_logo:
|
|
|
|
pop %ebp # get out_buffer and keep in bp
|
|
mov %ebp,%ecx # move out_buffer to ecx
|
|
|
|
call write_stdout # print the logo
|
|
|
|
#
|
|
# Setup
|
|
#
|
|
setup:
|
|
mov $strcat,%edx # use edx as call pointer
|
|
|
|
|
|
#==========================
|
|
# PRINT VERSION
|
|
#==========================
|
|
|
|
# push $SYSCALL_UNAME # uname syscall
|
|
# pop %eax # in 3 bytes
|
|
# mov $uname_info,%ebx # uname struct
|
|
# int $0x80 # do syscall
|
|
|
|
mov %ebp,%edi # point %edi to out_buffer
|
|
|
|
mov $(uname_info+U_SYSNAME),%esi # os-name from uname "Linux"
|
|
call *%edx # call strcat
|
|
|
|
mov $ver_string,%esi # source is " Version "
|
|
call *%edx # call strcat
|
|
push %esi # save our .txt pointer
|
|
|
|
mov $(uname_info+U_RELEASE),%esi # version from uname "2.4.1"
|
|
call *%edx # call strcat
|
|
|
|
pop %esi # restore .txt pointer
|
|
# source is ", Compiled "
|
|
call *%edx # call strcat
|
|
push %esi # store for later
|
|
|
|
mov $(uname_info+U_VERSION),%esi # compiled date
|
|
call *%edx # call strcat
|
|
|
|
mov %ebp,%ecx # move out_buffer to ecx
|
|
|
|
mov $0xa,%ax # store linefeed on end
|
|
stosw # and zero
|
|
|
|
call *%edx # call strcat
|
|
|
|
call center_and_print # center and print
|
|
|
|
#===============================
|
|
# Middle-Line
|
|
#===============================
|
|
|
|
#=========
|
|
# Load /proc/cpuinfo into buffer
|
|
#=========
|
|
|
|
push %edx # save call pointer
|
|
|
|
# push $SYSCALL_OPEN # load 5 [ open() ]
|
|
# pop %eax # in 3 bytes
|
|
|
|
# mov $cpuinfo,%ebx # '/proc/cpuinfo'
|
|
# xor %ecx,%ecx # 0 = O_RDONLY <bits/fcntl.h>
|
|
# cdq # clear edx in clever way
|
|
# int $0x80 # syscall. fd in eax.
|
|
# we should check that eax>=0
|
|
|
|
# mov %eax,%ebx # save our fd
|
|
|
|
# push $SYSCALL_READ # load 3 = read()
|
|
# pop %eax # in 3 bytes
|
|
|
|
mov $disk_buffer,%ecx
|
|
|
|
# mov $16,%dh # 4096 is maximum size of proc file #)
|
|
# we load sneakily by knowing
|
|
# 16<<8 = 4096. be sure edx clear
|
|
|
|
|
|
# int $0x80
|
|
|
|
# push $SYSCALL_CLOSE # close (to be correct)
|
|
# pop %eax
|
|
# int $0x80
|
|
|
|
#=============
|
|
# Number of CPUs
|
|
#=============
|
|
number_of_cpus:
|
|
|
|
xor %ebx,%ebx # chip count
|
|
|
|
# $disk_buffer still in ecx
|
|
bogo_loop:
|
|
mov (%ecx), %eax # load 4 bytes into eax
|
|
inc %ecx # increment pointer
|
|
|
|
cmp $0,%al # check for end of file
|
|
je done_bogo
|
|
|
|
# Grrr, due to a bug in binutils 2.18.50.0.9
|
|
# (which unfortunately shipped with Fedora 10)
|
|
# http://sourceware.org/bugzilla/show_bug.cgi?id=6878
|
|
# We can't use the apostrophe character
|
|
|
|
# cmp $('o'<<24+'g'<<16+'o'<<8+'b'),%eax
|
|
cmp $(0x6f<<24+0x67<<16+0x6f<<8+0x62),%eax
|
|
# "bogo" in little-endian
|
|
|
|
jne bogo_loop # if not equal, keep going
|
|
|
|
inc %ebx # otherwise, we have a bogo
|
|
inc %ebx # times two for future magic
|
|
jmp bogo_loop
|
|
|
|
done_bogo:
|
|
lea one-6(%ebx,%ebx,2), %esi
|
|
# Load into esi
|
|
# [one]+(num_cpus*6)
|
|
#
|
|
# the above multiplies by three
|
|
# esi = (ebx+(ebx*2))
|
|
# and we double-incremented ebx
|
|
# earlier
|
|
|
|
mov %ebp,%edi # move output buffer to edi
|
|
|
|
pop %edx # restore call pointer
|
|
call *%edx # copy it (call strcat)
|
|
|
|
# mov $' ',%al # print a space
|
|
mov $0x20,%al # print a space
|
|
stosb
|
|
|
|
push %ebx # store cpu count
|
|
push %edx # store strcat pointer
|
|
|
|
#=========
|
|
# MHz
|
|
#=========
|
|
print_mhz:
|
|
# mov $('z'<<24+'H'<<16+'M'<<8+' '),%ebx
|
|
mov $(0x7a<<24+0x48<<16+0x4d<<8+0x20),%ebx
|
|
# find ' MHz' and grab up to .
|
|
# we are little endian
|
|
# mov $'.',%ah
|
|
mov $0x2e,%ah
|
|
|
|
# below is same as "sub $(strcat-find_string),%edx
|
|
# gas won't let us force the one-byte constant
|
|
.byte 0x83,0xEA,strcat-find_string
|
|
|
|
call *%edx # call find string
|
|
|
|
mov %ebx,%eax # clever way to get MHz in, sadly
|
|
ror $8,%eax # not any smaller than a mov
|
|
stosl
|
|
|
|
#=========
|
|
# Chip Name
|
|
#=========
|
|
chip_name:
|
|
|
|
# because of ugly newer cpuinfos from intel I had to hack this
|
|
# now we grab the first two words in the name field and use that
|
|
# it works on all recent Intel and AMD chips. Older things
|
|
# might choke
|
|
|
|
# mov $('e'<<24+'m'<<16+'a'<<8+'n'),%ebx
|
|
mov $(0x65<<24+0x6d<<16+0x61<<8+0x6e),%ebx
|
|
# find 'name\t: ' and grab up to \n
|
|
# we are little endian
|
|
# mov $' ',%ah
|
|
mov $0x20,%ah
|
|
call *%edx # print first word
|
|
stosb # store a space
|
|
call skip_spaces # print next word
|
|
|
|
pop %edx
|
|
pop %ebx # restore chip count
|
|
pop %esi
|
|
|
|
call *%edx # ' Processor'
|
|
cmpb $2,%bl
|
|
jne print_s
|
|
inc %esi # if singular, skip the s
|
|
print_s:
|
|
call *%edx # 's, '
|
|
|
|
push %esi # restore the values
|
|
push %edx
|
|
|
|
#========
|
|
# RAM
|
|
#========
|
|
|
|
# push $SYSCALL_SYSINFO # sysinfo() syscall
|
|
# pop %eax
|
|
# mov $sysinfo_buff,%ebx
|
|
# int $0x80
|
|
|
|
mov (sysinfo_buff+S_TOTALRAM),%eax # size in bytes of RAM
|
|
shr $20,%eax # divide by 1024*1024 to get M
|
|
adc $0, %eax # round
|
|
|
|
|
|
call num_to_ascii
|
|
|
|
pop %edx # restore strcat pointer
|
|
|
|
pop %esi # print 'M RAM, '
|
|
call *%edx # call strcat
|
|
|
|
push %esi
|
|
|
|
|
|
#========
|
|
# Bogomips
|
|
#========
|
|
|
|
# mov $('s'<<24+'p'<<16+'i'<<8+'m'),%ebx
|
|
mov $(0x73<<24+0x70<<16+0x69<<8+0x6d),%ebx
|
|
# find 'mips\t: ' and grab up to \n
|
|
mov $0xa,%ah
|
|
call find_string
|
|
|
|
pop %esi # bogo total follows RAM
|
|
|
|
call *%edx # call strcat
|
|
|
|
push %esi
|
|
|
|
mov %ebp,%ecx # point ecx to out_buffer
|
|
|
|
|
|
call center_and_print # center and print
|
|
|
|
#=================================
|
|
# Print Host Name
|
|
#=================================
|
|
|
|
mov %ebp,%edi # point to output_buffer
|
|
|
|
mov $(uname_info+U_NODENAME),%esi # host name from uname()
|
|
call *%edx # call strcat
|
|
|
|
# ecx is unchanged
|
|
call center_and_print # center and print
|
|
|
|
pop %ecx # (.txt) pointer to default_colors
|
|
|
|
call write_stdout
|
|
|
|
|
|
#================================
|
|
# Exit
|
|
#================================
|
|
exit:
|
|
xor %ebx,%ebx
|
|
xor %eax,%eax
|
|
inc %eax # put exit syscall number (1) in eax
|
|
int $0x80 # and exit
|
|
|
|
|
|
#=================================
|
|
# FIND_STRING
|
|
#=================================
|
|
# ah is char to end at
|
|
# ebx is 4-char ascii string to look for
|
|
# edi points at output buffer
|
|
|
|
find_string:
|
|
|
|
mov $disk_buffer-1,%esi # look in cpuinfo buffer
|
|
find_loop:
|
|
inc %esi
|
|
cmpb $0, (%esi) # are we at EOF?
|
|
je done # if so, done
|
|
|
|
cmp (%esi), %ebx # do the strings match?
|
|
jne find_loop # if not, loop
|
|
|
|
# ! if we get this far, we matched
|
|
|
|
find_colon:
|
|
lodsb # repeat till we find colon
|
|
cmp $0,%al # this is actually smaller code
|
|
je done # than an or ecx/repnz scasb
|
|
|
|
# cmp $':',%al
|
|
cmp $0x3a,%al
|
|
jne find_colon
|
|
|
|
|
|
skip_spaces:
|
|
lodsb # skip spaces
|
|
cmp $0x20,%al # Loser new intel chips have lots??
|
|
je skip_spaces
|
|
|
|
store_loop:
|
|
cmp $0,%al
|
|
je done
|
|
cmp %ah,%al # is it end string?
|
|
je almost_done # if so, finish
|
|
# cmp $'\n',%al # also end if linefeed
|
|
cmp $0xa,%al # also end if linefeed
|
|
je almost_done
|
|
stosb # if not store and continue
|
|
lodsb # load value
|
|
jmp store_loop
|
|
|
|
almost_done:
|
|
|
|
movb $0, (%edi) # replace last value with NUL
|
|
done:
|
|
ret
|
|
|
|
|
|
#================================
|
|
# strcat
|
|
#================================
|
|
|
|
strcat:
|
|
lodsb # load a byte from [ds:esi]
|
|
stosb # store a byte to [es:edi]
|
|
cmp $0,%al # is it zero?
|
|
jne strcat # if not loop
|
|
dec %edi # point to one less than null
|
|
ret # return
|
|
|
|
#==============================
|
|
# center_and_print
|
|
#==============================
|
|
# string to center in ecx
|
|
|
|
center_and_print:
|
|
push %edx
|
|
push %ecx # save the string pointer
|
|
inc %edi # move to a clear buffer
|
|
push %edi # save for later
|
|
|
|
# mov $('['<<8+27),%ax # we want to output ^[[
|
|
mov $(0x5b<<8+27),%ax # we want to output ^[[
|
|
stosw
|
|
|
|
cdq # clear dx
|
|
|
|
str_loop2: # find end of string
|
|
inc %edx
|
|
cmpb $0,(%ecx,%edx) # repeat till we find zero
|
|
jne str_loop2
|
|
|
|
push $81 # one added to cheat, we don't
|
|
# count the trailing '\n'
|
|
pop %eax
|
|
|
|
cmp %eax,%edx # see if we are >=80
|
|
jl not_too_big # if so, don't center
|
|
push $80
|
|
pop %edx
|
|
|
|
not_too_big:
|
|
sub %edx,%eax # subtract size from 80
|
|
|
|
shr %eax # then divide by 2
|
|
|
|
call num_to_ascii # print number of spaces
|
|
# mov $'C',%al # tack a 'C' on the end
|
|
mov $0x43,%al # tack a 'C' on the end
|
|
# ah is zero from num_to_ascii
|
|
stosw # store C and a NULL
|
|
pop %ecx # pop the pointer to ^[[xC
|
|
|
|
call write_stdout # write to the screen
|
|
|
|
done_center:
|
|
pop %ecx # restore string pointer
|
|
# and trickily print the real string
|
|
|
|
pop %edx
|
|
|
|
#================================
|
|
# WRITE_STDOUT
|
|
#================================
|
|
# ecx has string
|
|
# eax,ebx,ecx,edx trashed
|
|
write_stdout:
|
|
push %edx
|
|
push $SYSCALL_WRITE # put 4 in eax (write syscall)
|
|
pop %eax # in 3 bytes of code
|
|
|
|
cdq # clear edx
|
|
|
|
xor %ebx,%ebx # put 1 in ebx (stdout)
|
|
inc %ebx # in 3 bytes of code
|
|
|
|
# another way of doing this: lea 1(%edx), %ebx
|
|
|
|
str_loop1:
|
|
inc %edx
|
|
cmpb $0,(%ecx,%edx) # repeat till zero
|
|
jne str_loop1
|
|
|
|
int $0x80 # run the syscall
|
|
pop %edx
|
|
ret
|
|
|
|
##############################
|
|
# num_to_ascii
|
|
##############################
|
|
# ax = value to print
|
|
# edi points to where we want it
|
|
|
|
num_to_ascii:
|
|
push $10
|
|
pop %ebx
|
|
xor %ecx,%ecx # clear ecx
|
|
div_by_10:
|
|
cdq # clear edx
|
|
div %ebx # divide
|
|
push %edx # save for later
|
|
inc %ecx # add to length counter
|
|
or %eax,%eax # was Q zero?
|
|
jnz div_by_10 # if not divide again
|
|
|
|
write_out:
|
|
pop %eax # restore in reverse order
|
|
add $0x30, %al # convert to ASCII
|
|
stosb # save digit
|
|
loop write_out # loop till done
|
|
ret
|
|
|
|
#===========================================================================
|
|
# section .data
|
|
#===========================================================================
|
|
.data
|
|
|
|
ver_string: .ascii " Version \0"
|
|
compiled_string: .ascii ", Compiled \0"
|
|
processor: .ascii " Processor\0"
|
|
s_comma: .ascii "s, \0"
|
|
ram_comma: .ascii "M RAM, \0"
|
|
bogo_total: .ascii " Bogomips Total\n\0"
|
|
|
|
default_colors: .ascii "\033[0m\n\n\0"
|
|
|
|
cpuinfo: .ascii "/proc/cpuinfo\0"
|
|
|
|
|
|
one: .ascii "One\0\0\0"
|
|
two: .ascii "Two\0\0\0"
|
|
three: .ascii "Three\0"
|
|
four: .ascii "Four\0"
|
|
|
|
.include "logo.lzss_new"
|
|
|
|
disk_buffer:
|
|
.ascii "processor : 0\n"
|
|
.ascii "vendor_id : AuthenticAMD\n"
|
|
.ascii "cpu family : 6\n"
|
|
.ascii "model : 6\n"
|
|
.ascii "model name : AMD Athlon(tm) XP 2000+\n"
|
|
.ascii "stepping : 2\n"
|
|
.ascii "cpu MHz : 1665.267\n"
|
|
.ascii "cache size : 256 KB\n"
|
|
.ascii "fdiv_bug : no\n"
|
|
.ascii "hlt_bug : no\n"
|
|
.ascii "f00f_bug : no\n"
|
|
.ascii "coma_bug : no\n"
|
|
.ascii "fpu : yes\n"
|
|
.ascii "fpu_exception : yes\n"
|
|
.ascii "cpuid level : 1\n"
|
|
.ascii "wp : yes\n"
|
|
.ascii "flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 mmx fxsr sse syscall mmxext 3dnowext 3dnow up\n"
|
|
.ascii "bogomips : 3330.53\n"
|
|
.ascii "clflush size : 32\n"
|
|
.ascii "power management: ts\n\0"
|
|
|
|
uname_info:
|
|
.ascii "Linux\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
.ascii "tobler\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
.ascii "2.6.29\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
.ascii "#1 SMP Mon May 4 09:51:54 EDT 2009\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
.ascii "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
|
|
|
|
|
sysinfo_buff:
|
|
.long 0,0,0,0,512*1024*1024,0,0,0,0
|
|
.long 0,0,0,0,0,0,0,0,0
|
|
|
|
#============================================================================
|
|
# section .bss
|
|
#============================================================================
|
|
.bss
|
|
|
|
.lcomm text_buf, (N+F-1)
|
|
.lcomm out_buffer,16384
|
|
|
|
|
|
|
|
|
|
|