1

This is a program given in the book 'Programming from the ground up' by Jonathan Bartlett to find the maximum number in a list:

#PURPOSE: This program finds the maximum number of a
# set of data items.
#
#VARIABLES: The registers have the following uses:
#
# %edi - Holds the index of the data item being examined
# %ebx - Largest data item found
# %eax - Current data item
#
# The following memory locations are used:
#
# data_items - contains the item data. A 0 is used
# to terminate the data
#
.section .data
data_items:                    #These are the data items
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi                  # move 0 into the index register
movl data_items(,%edi,4), %eax # load the first byte of data
movl %eax, %ebx                # since this is the first item, %eax is
                               # the biggest
start_loop:                    # start loop
cmpl $0, %eax                  # check to see if we’ve hit the end
je loop_exit
incl %edi                      # load next value
movl data_items(,%edi,4), %eax
cmpl %ebx, %eax                # compare values
jle start_loop                 # jump to loop beginning if the new
# one isn’t bigger
movl %eax, %ebx                # move the value as the largest

unfortunately the assembly programs given in the book are for 32 bit processors FWIU. So I'm translating the programs for 64 bit with some help from https://cs.lmu.edu/~ray/notes/gasexamples/. Here is my code(which is not working) for 64 bit systems:

#variables: the registers have the following uses:
# %rdx - holds the index of the data item being examined
# %rbx - largest data item found
# %rcx - current data item
# the following memory locations are used:
# data_items - contains the item data. 0 is used to terminate the data.
data_items:
        .long 8,9,3,4,15,8,0

.global _start
.text

_start:
        mov $0, %rdx                            # move 0 into the index register
        mov data_items(,%rdx,4), %rcx           # load the first byte of data
        mov %rcx, %rbx                          # since this is the first item, %rcx is the biggest

start_loop:
        cmp $0, %rcx                            # check to see if we've hit the end
        je loop_exit
        inc %rdx                                # load next value
        mov data_items(,%rdx,4), %rcx
        cmp %rbx, %rcx
        jle start_loop
        mov %rcx, %rbx                          # move the value as the largest
        jmp start_loop

loop_exit:
        #%rdi is the status code for the exit system call
        mov $60, %rax
        mov %rbx, %rdi                          # moving the final value in %rbx to %rdi to return
        syscall     

What is wrong in my code?

I suspect that .long doesn't work the same way in 64 bit assembly code.

I tried to debug the code in gdb here is the output:

Reading symbols from ./a.out...

(gdb) break 1
Breakpoint 1 at 0x401000: file max.s, line 11.
(gdb) run
Starting program: /home/hackasaur/Desktop/assembly/a.out

Breakpoint 1, _start () at max.s:11
11              mov $0, %rdx                                                                            # move 0 into the index register
(gdb)stepi
 12              mov data_items(,%rdx,4), %rcx           # load the first byte of data
(gdb) info registers
rax            0x0                 0
rbx            0x0                 0
rcx            0x0                 0
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x0                 0x0
rsp            0x7ffffffee160      0x7ffffffee160
r8             0x0                 0
r9             0x0                 0
r10            0x0                 0
r11            0x0                 0
r12            0x0                 0
r13            0x0                 0
r14            0x0                 0
r15            0x0                 0
rip            0x401007            0x401007 <_start+7>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0
(gdb) stepi
13              mov %rcx, %rbx                                                                  # since this is the first item, %rcx is the biggest
(gdb) info registers
rax            0x0                 0
rbx            0x0                 0
rcx            0x900000008         38654705672
rdx            0x0                 0
rsi            0x0                 0
rdi            0x0                 0
rbp            0x0                 0x0
rsp            0x7ffffffee160      0x7ffffffee160
r8             0x0                 0
r9             0x0                 0
r10            0x0                 0
r11            0x0                 0
r12            0x0                 0
r13            0x0                 0
r14            0x0                 0
r15            0x0                 0
rip            0x40100f            0x40100f <_start+15>
eflags         0x202               [ IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0            

I found that there is this gibberish value 38654705672 getting loaded in rcx register in the line 12 mov data_items(,%rdx,4), %rcx instead of 8. Every time something is loaded using mov data_items(,%rdx,4), %rcx some big gibberish value is loaded.

I am using this command to assemble and link: as max.s -o max.o && ld max.o && ./a.out and I'm getting an exit code of 4 for the above list of numbers using echo $? which should be 15 in this case if it worked correctly.

Manik
  • 573
  • 1
  • 9
  • 28
  • 2
    The array elements are still 32-bit so you should be doing 32-bit loads and compares on the data with 32-bit registers, only using 64-bit operand-size (and versions of register names) for the pointer math. `mov data_items(,%rdx,4), %rcx` loads 2 adjacent elements. Look at compiler output for an example if you write this in C for an `int[]` array: https://godbolt.org/ – Peter Cordes Nov 03 '20 at 03:37
  • 2
    "I suspect that .long doesn't work the same way in 64 bit assembly code." Au contraire, it works exactly the same - it assembles a 32-bit value, yet as Peter says your code treats them as 64-bit. Yes, this means that it doesn't necessarily match the size of C's `long` type. – Nate Eldredge Nov 03 '20 at 03:38
  • Look at the hex value, not decimal. It makes sense there: `0x900000008` makes it clear you're just loading two 32-bit elements into 1 register, resulting in `9<<32 | 8`. Yes the decimal value is gibberish because 10 isn't a power of 2. – Peter Cordes Nov 03 '20 at 08:49
  • Related: [In this x86-64 instruction encoding documentation, what's the use of having 8, 16, 32, 64 bit GPRs?](https://stackoverflow.com/q/64482535) and [64 bit assembly, when to use smaller size registers](https://stackoverflow.com/q/6577458) – Peter Cordes Nov 03 '20 at 09:52
  • And found a nearly exact duplicate: [Assembly code to return smallest integer in array instead randomly returns either last or second to last number](https://stackoverflow.com/q/60358473) is min instead of max and NASM syntax, but exactly the same problem: doing 64-bit qword loads from 32-bit dword data (aka `.long` aka C `int[]`). – Peter Cordes Nov 03 '20 at 09:59

0 Answers0