# Program to find the maximum number/factor in a list

I have written the following basic assembly program to find the maximum number in a list divisible by a number. Here is what I have thus far:

# Program: given a list or integers and a factor
# Find the max number in the list that the factor divides
# For example: INPUT: [3,9,50,27], factor: 3 | OUTPUT: 27
.section .rodata
nums:   .long 3,9,50,27,-1
factor: .long 3

.section .data
cur_value:  .long -1

# first three args: %edi, %esi, %edx
.section .text
.globl _start
_start:

# SETUP
# %r8 will store the array index
# %r11 will store the max value
# %esi will store the factor/divisor.
mov $0, %r10d mov$0,     %r11d
mov factor, %esi

loop:

# get current value and store it in %rdi
# we'll also update our variable for cur_value
mov nums(, %r10d, 4), %edi
cmp $-1, %edi je exit movl %edi, cur_value # Call the function and increment the aray index call is_divisible_by inc %r10d # if it was NOT divisible (rax = False or 0) jump back to the beginning cmp$0, %rax
je loop

# if it was divisible, check to make sure it's larger than the current max
cmp %r11d, cur_value
jl loop
mov cur_value, %r11d
jmp loop
exit:
mov %r11d, %edi
mov $60, %eax syscall is_divisible_by: # Return 0 (false) if not divisible; 1 (true) if divisible # A (dividend, %eax) / B (divisor) # dividend needs to first be moved into eax mov %edi, %eax # divide by a register, immediate, or memory address # this is unsigned (positive), use idiv for signed div %esi # the resultant integer quotient goes in %eax, and the remainder goes in %edx # if %rdx is zero it means A is divisible by B: we don't care about %eax mov$0, %eax

cmp $0, %edx jne end mov$1, %rax

end:
ret



It's compiled using:

$as file.s -o file.o && ld file.o -o file$ ./file; echo $? # 27  Here are a few particular questions related to this: 1. Is it common to use named variables (such as cur_value in .section .data) or not? I use them while learning a bit so it's easier to view the value of an easily-rememberable entity, i.e., I can just do x &cur_value in gdb to see what it is. 2. What is the suggested way to handle an if statement. I've tried to do this in the is_divisible_by function -- setting it to $0 by default and then 'overwriting' it if the true condition is met. -- but this seems pretty hacky. I suppose another way to do it would be something like:

  cmp $0, %edx je set_true set_false: mov$0, %eax
jmp clean_up
set_true:
mov \$1, %eax
jmp clean_up
clean_up:
ret

3. Is it common to have end-labels on functions and such? I find myself often adding an end or whatever to be able to 'exit' things easily.

4. For labels within a main label (such as exit or end or set_true etc.), what is a good way to name these? I see gcc uses something like .L1029 but that seems not-too-friendly when writing my own and having to remember then.

5. Would any of the above be better done 'on the stack' rather than using registers or named variables? I find it a bit more difficult to use the stack than registers as you cannot do something like mov mem1, mem2

6. Finally, how could I extract the is_divisible_by function into another file and call it from within this main file.s file?

• As stated in the guidelines, please do not edit the question after you have received an answer. Sep 16, 2020 at 21:23

You have two independent conditions that must be satisfied before updating cur_val.

1. The number must be divisible by factor
2. The number must be larger than cur_val

If the first test fails, you don't bother doing the second test.

How many instruction (or better cycles) does it take to do each test?

Given a long non-monotonic list, you may save considerable time simply by reversing these two tests.

• sorry I've updated the question. The elements in the list can be in any order not just a sorted list. Also, regarding How many instruction (or better cycles) does it take to do each test -- how can I find out how many cycles a section of code takes? I'm very new to assembly and have always wondered about that? Sep 16, 2020 at 18:45
• That is a very difficult question, and can depends on CPU version, cache, CPU -vs- Memory bus clock speed, and so on. You'd have to consult the CPU spec sheet, motherboard configuration. But a fair guess is cmp & jl takes way less than call is_divisible_by, cmp & je will take. Sep 16, 2020 at 21:08
• I see. Do you want to add a bit of code to your answer with how you'd suggest implementing it? Sep 17, 2020 at 23:32
• @samuelbrody1249 Sorry, no. I'm reasonably proficient reading code, but writing assembly I haven't done since 80486 days. Sep 18, 2020 at 0:10
• @AJNeufedl -- I see, ok thanks for the feedback though! Sep 18, 2020 at 2:15