Skip to content

Instantly share code, notes, and snippets.

@dstein64
Created October 29, 2017 04:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dstein64/890e02e8e277f17d931c8a250ceaaf44 to your computer and use it in GitHub Desktop.
Save dstein64/890e02e8e277f17d931c8a250ceaaf44 to your computer and use it in GitHub Desktop.
/*** echo.s ***/
// Description
// echo - print arguments to stdout
// Synopsis
// echo [STRING]...
// Build
// $ as --32 -o echo.o echo.s
// $ ld -m elf_i386 -o echo echo.o
.section .text
# ************************************
# * print macro
# * Caller is responsible for setting
# * %ecx and %edx, and saving %eax and
# * %ebx if necessary.
# ************************************
.macro print
movl $4, %eax
movl $1, %ebx
int $0x80
.endm
# ************************************
# * int strlen(char* str);
# * Returns the length of a string.
# ************************************
.type strlen, @function
strlen:
pushl %ebp
movl %esp, %ebp
movl $0, %eax # Index
movl 8(%ebp), %ecx # Address of str
strlen_loop:
movb (%ecx,%eax,1), %dl # Current char
cmpb $0, %dl
je strlen_end
incl %eax
jmp strlen_loop
strlen_end:
movl %ebp, %esp
popl %ebp
ret
.section .rodata
newline_char:
.ascii "\n"
space_char:
.ascii " "
.section .text
# ************************************
# * echo [STRING]...
# * Prints the string(s) to stdout.
# ************************************
.globl _start
_start:
movl %esp, %ebp
# Local variables (offset from %ebp)
.equ index, -4 # Stack index being operated on
.equ address, -8 # Current arg address
.equ length, -12 # Current arg length
subl $12, %esp
# Start at index 1 (this skips argc)
movl $1, index(%ebp)
echo_loop:
# Set address local variable
movl index(%ebp), %ecx
movl 4(%ebp, %ecx, 4), %eax
movl %eax, address(%ebp)
# Check if we're done (reached a NULL pointer)
cmpl $0, address(%ebp)
je echo_loop_end
# Calculate length of string
pushl address(%ebp)
call strlen
addl $4, %esp
# Set length local variable
movl %eax, length(%ebp)
# Print leading space if index > 1
cmpl $1, index(%ebp)
jle leading_space_end
movl $space_char, %ecx
movl $1, %edx
print
leading_space_end:
# Print current argument
movl address(%ebp), %ecx
movl length(%ebp), %edx
print
incl index(%ebp)
jmp echo_loop
echo_loop_end:
# Print newline char
movl $newline_char, %ecx
movl $1, %edx
print
# Exit
movl $1, %eax
movl $0, %ebx
int $0x80
Copy link

ghost commented Jan 5, 2023

This program works very well, but when I ./echo -e "Multiple\nlines\nin\noutput" the \n newline doesn't work

@dstein64
Copy link
Author

dstein64 commented Jan 5, 2023

Hi @blk10-droid, this implementation only supports echo's most basic functionality, displaying the arguments. There is no support for command line flags like -e.

To use newlines, e.g., with a bash shell, you can use ANSI-C Quoting.

./echo $'Multiple\nlines\nin\noutput'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment