1 / 24

Crafting a ‘demo’ program

A demo program development cycle walk-through for illustrating steps in modifying Linux terminal behavior in assembly language. Learn about new Pentium instructions and tty capability reprogramming.

ewindsor
Download Presentation

Crafting a ‘demo’ program

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Crafting a ‘demo’ program A ‘walk-through’ of the program development cycle for an example in assembly language

  2. Our purpose • We want to illustrate the steps that a Linux program needs to take when modifying the normal ‘canonical mode’ terminal behavior • We want to write it in assembly language • Our Project #2 involves something similar • Here we want to ‘Keep It Simple’ (KISS) • But yet we want to show the essentials • We might see new Pentium instructions

  3. Just a tiny change • Users can normally ‘cancel’ a program • They can do it by typing <CONTROL>-C • It’s important for stopping “infinite loops” • The system sends a ‘termination’ signal • This avoids the need for a system ‘reboot’ • But we can ‘reprogram’ this tty capability • We just turn off a bit in the ‘c_lflag’ field

  4. Our ‘nocbreak.s’ demo • Step 1: get the terminal’s initial settings • Step 2: save a copy of these settings • Step 3: modify the ISIG bit in ‘c_lflag’ field • Step 4: install the ‘modified’ tty settings • Step 5: let user do some keyboard input • Step 6: reinstall original terminal settings • Step 7: Quit (i.e., return control to Linux)

  5. Step 1: Get ‘tty’ settings • We can use the ‘tcgetattr()’ function • It’s part of the system’s runtime library • Use ‘man’ command to see how it’s called • Here’s its function prototype: int tcgetattr( int fileno, struct termios &tty ); • We can call it using assembly language: • Push the arguments (in right-to-left order) • Call the function: call tcgetattr • Discard the arguments from the stack

  6. Here’s the code .section .data ttywrk: .space 60 # for ‘termios’ object .section .text pushl $ttywrk # push the address pushl $0 # push device-ID call tcgetattr # call runtime library addl $8, %esp # discard arguments

  7. Step 2: copy the object • We can setup a loop to perfortm copying • Loop can copy structure one byte at a time • Total number of bytes is loop-count (60) • Put source-address into a cpu register • Put dest’n-address into a cpu register • Advance addresses as each byte is copied • Use ‘loop’ opcode to decrement-and-jump

  8. Here’s the data .section .data ttysav: .space 60 # original structure ttywrk: .space 60 # our working copy

  9. And here’s the code .section .text movl $ttywrk, %esi # setup source addr movl $ttysav, %edi # setup dest’n addr movl $60, %ecx # setup loop-count nxmv: # label the loop-body movb (%esi), %al # copy src byte to AL movb %al, (%edi) # copy AL to dest’n incl %esi # advance src-addr incl %edi # advance dst-addr loop nxmv # finish coping bytes

  10. Step 3: modify the flag-bit • We know where the ‘c_lflag’ field is • It’s starts 12 bytes into ‘termios’ structure • We got this info from our ‘ttyinfo.cpp’ demo • Similarly we can find that ISIG bit is bit #1 • We want to “reset” this bit (i.e.,clear it to 0) • We could use a bitwise AND operation • But Pentium offers us another way (BTR)

  11. Here’s the code .equ ISIG, 0 # symbolic constant .section .data ttywrk: .space 60 # for termios object .section .text movl $12, (%edx) # offset for ‘c_lflag’ btr #ISIG, ttywrk(%edx) # resets bit #1

  12. Brief digression • Other Pentium bit-manipulations: BTS (bit-set) BTR (bit-reset) BTC (bit-complement) BT (bit-test) • These operations all have this “side effect”: • the previous bit-value gets transferred to the CF-bit (Carry Flag) within the Pentium’s EFLAGS register • Why? So you can use JC (or JNC) afterward

  13. Step 4: Install new behavior • We can use the ‘tcsetattr()’ function • Use ‘man tcsetattr’ to see how its called • Requires three function arguments: • Device’s ID-number (i.e., 0 for keyboard) • A flag-value, to specify buffer-flushing • The address of the new ‘termios’ object • As usual, these arguments have to be pushed in reverse (i.e., right-to-left) order

  14. Here’s the function-call .section .text pushl $ttywrk # address of the object pushl $TCSAFLUSH # flag-value pushl $0 # keyboard’s device-ID call tcsetattr # call to runtime library addl $12, %esp # rebalance stack # NOTE: Similar code is used later in step 6

  15. Step 5: Try new tty behavior • We want to let the user type some input • In particular, we want to test <CTRL>-C • We’ve changed the normal tty handling • Prove <CTRL>-C won’t stop the program • Find out what the new response will be • We need program to ‘read’ from keyboard • Can use ‘read()’ from the runtime library

  16. How ‘read()’ works • Function’s prototype shows 3 arguments: • Device ID-number (e.g., 0 for the keyboard) • Address for an input-buffer (we create buffer) • Maximum number of bytes that will be read • In canonical mode, the ‘read()’ call won’t return until either the user hits <ENTER> or the maximum number of bytes have been transferred into the input-buffer

  17. So here’s the ‘read()’ call .section .data inchar: .space 1 # room for 1 byte .section .text pushl $1 # maximum bytes pushl $inchar # buffer’s address pushl $0 # keyboard’ ID call read # call to C library addl $12, %esp # discard arguments

  18. Testing for <EACAPE>-code • We needed a way to stop the program • Can’t quit by using <CONTROL>-C now • Our solution: quit by hitting <ESCAPE> • So program needs to test for its ascii-code • ASCII-code for ESCAPE-key equals 0x1B • Our loop includes a compare-and-branch

  19. Testing for the ‘exit’ condition .section .data inchar: .space 1 # buffer for user input .section .text again: … cmpb $0x1B, inchar # user typed ESC? jne again # no, reenter loop # otherwise, fall through to next instruction

  20. A ‘tweak’ for esthetics • When we tested our ‘nocbreak’ demo, we did not like the screen’s appearance • Our program’s final output was ‘garbled’ by the subsequent command-shell prompt • We wanted to make the output prettier • So we added a additional code-fragment • A ‘newline’ control-code gets printed after each keypress by the user (using ‘write()’)

  21. In-class exercises • Programmers can choose among several ways of accomplishing a particular task • Example: there’s more than one way to copy a 60-byte data-structure from one place in memory to another • We don’t have to do it one-byte-at-a-time • We don’t have to use both %esi and %edi • Try doing the copying in some other ways

  22. Using a common array-index • Here’s an idea for a different copying scheme .section .text xorl %esi, %esi # array-index movl $30, %ecx # word-count nxwm: movw ttywrk(%esi), %ax # fetch word movw %ax, ttysav(%esi) # store word addl $2, %esi # next word index loop nxwm

  23. Using a ‘scaled’ array-index # we use a ‘scaled index’ to do array-addressing .section .text xorl %esi, %esi # clear to zero movl $30, %ecx # loop-count nxwd: movw ttywrk( , %esi, 2), %ax movw %ax, ttysav( , %esi, 2) incl %esi # increment index loop nxwd:

  24. Exercise • Try to devise the ‘most efficient’ method you can think of for copying the 60-bytes • But what does ‘most efficient’ mean? • Using the fewest assembly statements? • Using the fewest cpu regisers? • Executing the fewest loop-iterations? • Will your “solution” be the same no matter what you think “most efficient” means?

More Related