EC

  • Edwin Chan
  • CV
  • CPSC 233
  • CPSC 331
  • CPSC 355
  • CPSC 581
  • Origami
  • Random

Tutorial 9 (Nov 21): External pointer arrays, command line arguments, atoi()

These two three topics are not required for A5a, but you need them for A5b. We will cover these in Monday/Tuesday tutorials.

[external.s][1440B]
[command.s][1140B]
[atoi.s][813B]

The first two examples are from Professor Manzara's slides, although I've added a few more comments.

External pointer arrays

I like to relate back to things you've already learned, especially because the topics in A5 are relatively simple if you understood A3 and A4. You've previously worked with arrays already, storing multiple integers. Each integer was 4 bytes long. Using a base address and an offset (calculated from the index), you were able to load and store to/from the array.

With an external pointer array, we store pointers rather than integers. Recall that a pointer is an object which "points to" another object. Essentially, a pointer contains an address. When we passed pointers into subroutines in A4, we stored addresses into x0-x7, with the registers x0-x7 becoming pointers. Now recall all the string literals we have used in every program so far, which follow this format:

stringName: .string "cpsc355"

stringName is a pointer to the address (or memory location) which contains the string "cpsc355". An external pointer array contains pointers. Since ARMv8 is a 64-bit architecture, addresses are 64-bits (or 8 bytes). For this reason, the contents of our array are dwords (8 bytes).

[external.s] External pointer arrays

// Credits: Professor Leonard Manzara
// Comments were modified, and macros were replaced with register equates (.req)

i_r    .req w19
base_r .req x20

       .text
fmt:   .string "season[%d] = %s\n" // String literals should not change during the program
                                   // and are placed in the .text (read-only) section

spr_m: .string "spring"            // each string is pointed to by its label
sum_m: .string "summer"
fal_m: .string "fall"
win_m: .string "winter"

          .data
season_m: .dword spr_m, sum_m, fal_m, win_m // This is an array of pointers
                                            // Each pointer (label) points to a string.
                                            // Because addresses in ARMv8 are 64-bits, we need
                                            // to use dwords (8 bytes = 64 bits).

          .text                             // Program code is read-only, goes in .text
          .balign 4                         // word align your program
          .global main
main:     stp x29, x30, [sp, -16]!
          mov x29, sp

          mov i_r, 0
          b test

          top: adrp x0, fmt                 // First argument to printf (string format)
          add x0, x0, :lo12:fmt

          mov w1, i_r                       // Index to loop through seasons array

          adrp base_r, season_m             // get the base address of our pointer array
          add base_r, base_r, :lo12:season_m

          // use loop index to calculate offset
          // SXTW (sign extend), then LSL 3 (multiply by 8)
          // Each address is 8 bytes hence multiply by 8
          ldr x2, [base_r, i_r, SXTW 3]

          bl printf                         // print the season loaded in x2

          add i_r, i_r, 1
          test: cmp i_r, 4                  // pre-test loop to print all the seasons
          b.lt top

          ldp x29, x30, [sp], 16
          ret

 
external pointers
external gdb

 

Command line arguments

Programs that can only take one input with a single output are not very useful. To provide different parameters, a program can take command line arguments, similar to how functions/subroutines can accept parameters. When we execute a program, we can include arguments like this:

./a5b 9 11 1990

These arguments are then passed into the main() subroutine. However, w0 DOES NOT contain the first argument. Instead, w0 contains the NUMBER of arguments that were passed in. In this case, there are four arguments: "./a5b", "9", "11", and "1990". The pointers to each argument are stored as an external pointer array, with x1 as the base address. Using x1 as the base address, and an index to calculate the offset, we can access each argument.

[command.s] Command line arguments

// Credits: Professor Leonard Manzara
//
// NOTE: To test the program, run the program normally but add some command line arguments.
// Example: ./a.out 1 2 3
// Example: ./a.out MM DD YYYY

i_r    .req w19 // index for our loop (integer)
argc_r .req w20 // arg-count, or number of arguments passed into main() (integer)
argv_r .req x21 // arv-values, the base address of an array of pointers
                // each pointer points to an argument

// To load the values of each argument, you first get the base address of argv. Then you
// use left shift the index i_r (multiply 8) and use that as an offset to get the pointer
// for the argument you want. Load from that pointer to get the value of the argument.

fmt:   .string "%s\n"

       .balign 4
       .global main
main:  stp x29, x30, [sp, -16]!
       mov x29, sp

       mov argc_r, w0                // copy argc (number of pointers)
       mov argv_r, x1                // copy argv (base address to an array containing the args)

       mov i_r, 0                    // i= 0
       b test

       top: adrp x0, fmt
       add x0, x0, :lo12:fmt         // set up 1st arg

       ldr x1, [argv_r, i_r, SXTW 3] // set up 2nd arg

       bl printf                     // call printf

       add i_r, i_r, 1               // i++
       test: cmp i_r, argc_r         // loop while i < argc
       b.lt top

       ldp x29, x30, [sp], 16
       ret

atoi(): converting ASCII string to an integer

When the user enters a number as a command line argument, it is saved as a string. To convert this into a number, we can use the atoi() function from the C library.

  1. Load the ASCII string from the command line arguments.
  2. Pass the string to atoi() in x0, which returns an int in w0.
[atoi.s] Converting ASCII string to an integer

// Converts a number from ASCII string to int
// Usage: ./a.out 12345
// Output: "The number you entered is: 12345"

      .text
fmt:  .string "The number you entered is: %d\n" // format takes an int variable

      .balign 4
      .global main
main: stp x29, x30, [sp, -16]!
      mov x29, sp

      mov w19, 1                                // the 1st arg (index 0) is the program name
                                                // we want the 2nd arg, the number entered

      ldr x0, [x1, w19, SXTW 3]                 // x1 is the base address to the external pointer
                                                // array containing pointers to all our args
                                                // w19 (1) is the index, SXTW 3 to calculate offset
      bl atoi                                   // convert ASCII string to integer, result in w0

      mov w1, w0                                // set up 2nd arg for printf
      adrp x0, fmt                              // set up 1st arg for printf
      add x0, x0, :lo12:fmt
      bl printf                                 // print the number

      mov w0, 0
      ldp x29, x30, [sp], 16
      ret

Timber by EMSIEN 3 Ltd BG
  • Edwin Chan
  • CV
  • CPSC 233
  • CPSC 331
  • CPSC 355
  • CPSC 581
  • Origami
  • Random