2

I'm having trouble writing what should be a simple character counting program. Here's the file with the .data section, as given by the author of Learn to Program with Assembly, which I'm following (I posted it in another question a few days ago):

.section .data

gkcname: .ascii "Gilbert Keith Chester\0"
jbname:  .ascii "Jonathan Bartlett\0"
cslname: .ascii "Clist Silver Lewis\0"
taname:  .ascii "Tommy Aquinas\0"
inname:  .ascii "Isaac Newn\0"
gmname:  .ascii "Gregory Mend\0"

.globl people, numpeople
numpeople: .quad (endpeople-people)/PERSON_RECORD_SIZE
people:
    .quad gkcname, 200, 10, 2, 74, 20
    .quad jbname,  280, 12, 2, 72, 44
    .quad cslname, 150,  8, 1, 68, 30
    .quad taname,  250, 14, 3, 75, 24
    .quad inname,  250, 10, 2, 70, 11
    .quad gmname,  180, 11, 5, 69, 65
endpeople:

.globl NAME_PTR_OFFSET, WEIGHT_OFFSET, SHOE_OFFSET
.globl HAIR_OFFSET, HEIGHT_OFFSET, AGE_OFFSET
.equ NAME_PTR_OFFSET, 0
.equ WEIGHT_OFFSET, 8
.equ SHOE_OFFSET, 16
.equ HAIR_OFFSET, 24
.equ HEIGHT_OFFSET, 32
.equ AGE_OFFSET, 40

.globl PERSON_RECORD_SIZE
.equ PERSON_RECORD_SIZE, 48

And here is the file with the .text section, which is the part I'm trying write myself:

.section .text

_start:
    movq $people, %rbx
    movq (%rbx), %rax
    movq numpeople, %rcx

mainloop:
    cmpq $0,  NAME_PTR_OFFSET(%rax)
    je endloop

    incq %rdi

loopcontrol:
    incq %rax
    jmp mainloop

endloop:
    movq $60, %rax
    syscall

Eventually the idea is to count the characters in each name and find which one is longest. That's the exercise. In C/C++ or Python, I'd have no issue with it. Right now, though, I'm just trying to get as far as counting the characters in the first name. I was trying to return that value via %rdi and ran into trouble already.

If I run movq NAME_PTR_OFFSET(%rax), %rdi, %rdi will return 71 (ASCII value for 'G', which is, indeed, the first letter of the first name), and if I incq %rax and then perform the same command, it will return 105 (ASCII for 'i'), so that's all working as expected. But somehow when I run it through the cmp command, something goes wrong.

The key command here (I think) is cmpq $0, NAME_PTR_OFFSET(%rax). What I'm going for with this, as you might guess, is to have %rdi increment by one each iteration through the loop until we reach the terminating null character ('\0', which is zero in ASCII). But when I run the program I get a value of 98 for %rdi, which I think is the total character count for all six names combined.

Also, to try to troubleshoot this, I ran cmpq $105, NAME_PTR_OFFSET(%rax) expecting that %rdi would come back with a value of one (105 is ASCII for 'i', the second character in the first name, so %rdi should increment once and then the loop should terminate). That gave me a segfault.

I'm sure this is something simple with my syntax or something, but I can't find a solution. The comparison functionality isn't working, and I can't figure out what I need to do differently.

8
  • 3
    You want cmpb (compare a byte item) not cmpq (compare a qword). Commented Oct 20 at 7:09
  • 1
    That was it. Thank you so much for your help. Really long question for such a short answer. :-) I used cmpb first but I think I had the arguments reversed at that time (my high-level-programming mind tells me the order of the arguments shouldn't matter for this command, so I had to look it up to understand how cmp actually works), and by the time I figured that out I had already moved on to trying cmp and cmpq. Anyways, much appreciated. Commented Oct 20 at 7:18
  • 3
    If I run movq NAME_PTR_OFFSET(%rax), %rdi, %rdi will return 71. No, DIL will have that value, the rest of RDI will have "ilbert ". You're making the same error as your last question, using an exit status to look at the low 8 bits of RDI instead of using a debugger. See the bottom of stackoverflow.com/tags/x86/info for GDB tips. Commented Oct 20 at 8:36
  • 1
    Also, your current code relies on RDI being initially 0, which is only true at _start in a statically-linked Linux executable, and then only as an implementation detail, not a documented guarantee. In a dynamic executable's _start, or in any function, RDI holds arbitrary garbage from its last use (e.g. from ld.so code that ran in your process before your _start.) Either put a comment documenting that code-golf size-saving hack, or put xor %edi, %edi before your strlen loop. Commented Oct 20 at 8:39
  • 2
    Unrelated issue: You probably want movq NAME_PTR_OFFSET(%rbx), %rax instead of movq (%rbx), %rax and then cmpb $0, (%rax) -- it does not make a difference in your case, since NAME_PTR_OFFSET happens to be 0. Commented Oct 20 at 14:16

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.