Assembly Advice

Created

Practical Advice for Assembly Programming

  • The .section directive specifies which “section” of the executable program assembled code or data will be placed in

Put things in the right place!

  • Code goes in .text
  • Read-only data such as string constants go in .rodata
  • Uninitialized (zero-filled) variables and buffers go in .bss
    • Use the .space directive to indicate how large these are
  • Initialized (non-zero-filled) variables and buffers go in .data
    • There are various directives such as .byte, .2byte, .4byte, etc. to specify initialized data values

Labels:

  • Labels are names representing addresses of code or data in memory

  • For functions and global variables, use appropriate names

    • Functions and data exported to other modules must be marked with .globl
  • For control-flow targets within a function, use local labels

    • These are labels which start with .L (dot, followed by upper case L)
    • The assembler will not add these to the module’s symbol table
    • Using “normal” labels for control flow makes debugging difficult because gdb thinks they are functions!

Using GDB

  • You can debug assembly programs using gdb!

  • “Debugging by adding print statements” is much less practical for assembly programs than programs in a high level language

    • Which isn’t to say it’s not possible or (occasionally) useful
  • Being able to use gdb confidently will greatly enhance your ability to develop working assembly language programs

  • Set breakpoints (break main, break myProg.S:123)

  • where: see current call stack

  • If you compiled your code with debugging symbols (i.e., using -g flag to gcc), next and step commands work as expected!

  • If code is compiled without debug symbols, it’s more difficult:

    • disassemble (or just disas): display assembly code of currentfunction
    • stepi: step to next instruction
    • nexti: step to next instruction (stepping over call instructions)
  • Set breakpoints (break main, break myProg.S:123)

  • where: see current call stack

  • If you compiled your code with debugging symbols (i.e., using -g flag to gcc), next and step commands work as expected!

  • If code is compiled without debug symbols, it’s more difficult:

    • disassemble (or just disas): display assembly code of current function
    • stepi: step to next instruction
    • nexti: step to next instruction (stepping over call instructions)
  • Use $ prefix to refer to registers (e.g., $rax, $edi, etc.)

  • Use print and casts to C data types when inspecting data:

  • Print 64 bit value %rsp points to: print *(unsigned long *)$rsp

  • Print character string %rdi points to: print (char *)$rdi

  • Print fourth element of array of int elements that %r12 points to: print ((int *)$r12)[3]

  • Print contents of %rcx is hexadecimal: print/x $rcx

Assembly Program Outline

.section .rodata
	// read only strings

.section .bss
	// zero-initialized global variables

.section .text

	.global main
main:
	subq $8, %rsp

.LinputLoop:
	// do stuff