Error #5: Unaligned word memory reference

2019-08-20 04:16发布

问题:

I am attempting to build an array of integers to represent edges (index of source | index of destination | weight) in an implementation of Dijkstra’s Algorithm using MIPS.

On running with rsim, I am getting an “unaligned word memory reference” error. I think I may be misunderstanding what memory alignment refers to. My .data is below

.data
.align 4

enterNode:          .asciiz "Enter the number of nodes: "
enterEdges:         .asciiz "Enter the number of edges: "
enterSource:        .asciiz "Enter source: "
enterDestination:   .asciiz "Enter destination: "
enterWeight:        .asciiz "Enter weight: "
newLine:            .asciiz "\n"
min_nodes:          .word 1
max_nodes:          .word 20
error1:             .asciiz "Invalid number of nodes. Must be between 1 and 20.\n"
error2:             .asciiz "Invalid number of edges. Must be between 0 and 400.\n"
edgeArr:            .space 4800
    # source | destination | weight
input:              .space 5

In the .text, I am looping for the number of edges to input the data into the array, but it seems the way I am referring to or calculating the address is incorrect.

addi    $t0, $zero, 0                   # Edge counter
la      $t1, edgeArr
addi    $t2, $zero, 0

loop:
    # Source
    addi    $v0, $zero, PRINT_STRING    # Print user prompt
    la      $a0, enterSource
    syscall
    addi    $v0, $zero, READ_INT        # Take user input
    syscall
    add     $t3, $t2, $t2               # Calculate address in array
    add     $t3, $t3, $t3
    add     $t3, $t1, $t3
    sw      $v0, ($t3)
    addi    $t2, $t2, 1

    # ...destination and weight are effectively identical to source...

    # Loop condition
    addi    $t0, $t0, 1
    slt     $t4, $t0, $s1
    bne     $t4, $zero, loop

I’ve looked at several similar questions but they don’t seem to quite address the portion I’m misunderstanding, and I could really benefit from a fresh pair of eyes looking at this.

回答1:

You have some strings between the .align 4 and your .word directive.

.align 4 pads to make the current position a multiple of 4. The total size of the strings are not a multiple of 4, so your .word directives are not at word-aligned memory addresses.

.data
.align 4
min_nodes:          .word 1
max_nodes:          .word 20

edgeArr:            .space 4800
    # source | destination | weight
input:              .space 5              # 5 bytes??


enterNode:          .asciiz "Enter the number of nodes: "
enterEdges:         .asciiz "Enter the number of edges: "
enterSource:        .asciiz "Enter source: "
enterDestination:   .asciiz "Enter destination: "
enterWeight:        .asciiz "Enter weight: "
newLine:            .asciiz "\n"
error1:             .asciiz "Invalid number of nodes. Must be between 1 and 20.\n"
error2:             .asciiz "Invalid number of edges. Must be between 0 and 400.\n"

If min_nodes is a build-time constant, define it with .equ instead of storing it in memory at all. (So you can use it as an immediate constant)

.equ  min_nodes, 1
.equ  max_nodes, 20

...
li   $t0, min_modes

Or sltiu $t1, $t0, min_modes to set $t1=1 if $t0 < min_nodes (unsigned), otherwise set it to zero. And BTW, you can do a range check with only one branch:

addui  $t1, $t0, -1
then compare against 19 (unsigned)

Values less than 1 will wrap to a large unsigned value (and compare greater than 19). Values greater than 20 will still be greater than 19.


You also don't need to mix your string constants with read-write values. If your assembler supports a .rodata or .section .rodata, your read-only strings go in the text segment of your executable so they're write-protected.