2021年4月11日星期日

Assembly: How to return a pointer?

The function inventory take an array of device pointers and call evaluate to find out what the variation is. The inventory function then returns a pointer that has the highest variation.

unsigned short evaluate(Struct Device *thing);    struct Device *inventory(struct Device *things[], int count);  

device.h:

struct Device{     char name[20];     short adjustments[8];     short avg;  }  

main.c:

#include <stdio.h>  #include <stdlib.h>    #include "device.h"    /* from device.h, shown here to make it easier to code  struct Device  {         char name[20];      short adjustments[8];      short avg;  };  */    struct Device things[] =  {      { "Museum Quality",{ 0, 1, 0, -1, 0, -1, 0, 1}, 1 },      { "Fell off truck",          { 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff},      2 },        /* the casts are there since C constants are ints and you can't make       * them shorts and negative numbers look like overflow */      { "Fell down stairs",      { 0x7ff0, (unsigned short)0x800f, 0x7ffe, (unsigned short)0x8001,       0x7ffd, (unsigned short)0x8002, 0x7fff, 0x7f00},       3 },        { "On left side",{ 10, 11, 10, 12, 10, 13, 10, 14}, 4 },      { "On right side",{ -300, -321, -320, -332, -320, -313, -310, -314}, 5 }  };      /*  struct Device *inventory(struct Device *things[], int count);  */            int main()  {        struct Device *pointers[1 + sizeof(things) / sizeof(things[0])]           = {NULL};      const int count =  sizeof(things) / sizeof(things[0]);        struct Device *worst = NULL;        int i;          for (i=0; i< count; i++)      {          printf("Loading %s into pointers\n", things[i].name);          pointers[i] = &things[i];      }      pointers[i] = NULL;              worst = inventory(pointers, count);        printf("main: The worst is %s\n", worst->name);          return(EXIT_SUCCESS);  }  

calibrate.s:

.file "calibrate.s"     #optional directive   .section .rodata    #required directives for rodata     .data       #required for file scope data: read-write program data               #of static storage class     .globl calibrate    #required directive for every function       .type calibrate, @function      #required directive      .text                  #required directive - code begins here   calibrate:           pushq %rbp          #stack housekeeping #1           movq %rsp, %rbp     #stack housekeeping #2                             movq $0, %r10           #initialize counter to 0          movq $0, %r11           #initialize sum to be 0          movswq 20(%rdi),%rcx    #initialize min to first element          movswq 20(%rdi),%rdx    #initialize max to first element     loop:          movswq 20(%rdi,%r10,2), %rax  #copy first parameter into rax          cmpq %rdx, %rax          jle skipmax          movq %rax, %rdx  skipmax:          cmpq %rcx, %rax          jge skipmin          movq %rax, %rcx  skipmin:              addq %rax, %r11                   incq %r10          cmpq $8,%r10          je exit   jmp loop        exit:          movq %r11, %rax          sarq $3, %rax          movl %eax, 36(%rdi)          subq %rcx, %rdx          movq %rdx, %rax          leave               #return stack to original values          ret             #return      .size calibrate, .-calibrate    #required directive  

evaluate.s:

.file "evaluate.s"      #optional directive   .section .rodata    #required directives for rodata   .LC0:      .string "\nevaluate: %s currently has an adjustment of %i\n"    .LC1:      .string "evaluate: new adjustment is %i, variability is %i\n"    .data       #required for file scope data: read-write program data               #of static storage class     .globl evaluate     #required directive for every function       .type evaluate, @function       #required directive      .text                  #required directive - code begins here   evaluate:           pushq %rbp          #stack housekeeping #1           movq %rsp, %rbp     #stack housekeeping #2                             pushq %r12           pushq %r13          pushq %r14            movq %rdi, %r14         #r14 stores the device struct          movq 36(%r14), %r13     #r13 stores the old avg          call calibrate                            movq %rax, %r12         #r12 stores variability          movq %r13, %rdx          movq %r14, %rsi         #copy the name to the second parameter          movq $.LC0, %rdi          movq $0, %rax          call printf                            movq %r12, %rdx          movq 36(%r14), %rsi    #copy new average to second parameter          movq $.LC1, %rdi          movq $0, %rax          call printf                            movq %r12, %rax          popq %r14          popq %r13          popq %r12           leave               #return stack to original values          ret             #return      .size evaluate, .-evaluate    #required directive  

inventory.s:

rdi is the parameter that holds an array of device pointers, #rbx is a copy of rdi, so it stores array of pointers of devices, #r12 stores count of valid pointers, #r14 stores max variation, #r15 stores the device pointer with the most variation.

    .file "inventory.s"     #optional directive       .section .rodata    #required directives for rodata       .LC0:          .string "\ninventory: The minimum variation is %i\n"            .LC1:          .string "inventory: The maximum variation is %i from %s\n"            .data       #required for file scope data: read-write program data                   #of static storage class             .globl inventory    #required directive for every function           .type inventory, @function      #required directive              .text                  #required directive - code begins here       inventory:                       pushq %rbp          #stack housekeeping #1           movq %rsp, %rbp     #stack housekeeping #2                             pushq %rbx          pushq %r12          pushq %r13          pushq %r14          pushq %r15            movq %rdi, %rbx         #rbx stores array pointer things          decq %rsi          movq %rsi, %r12         #r12 stores count of valid pointers          movq $32767, %r13       #r13 stores min variability          movq $0, %r14           #r14 store max variability          movq %rdi, %r15         #r15 stores pointer with most variable       loop:           movq (%rbx,%r12,8), %rdi          call evaluate                    cmpq %r14, %rax          jle skipmax          movq %rax, %r14          movq (%rbx, %r12,8), %r15   skipmax:          cmpq %r13, %rax          jge skipmin          movq %rax, %r13   skipmin:          decq %r12          cmpq $0, %r12          jge loop                    movq %r13, %rsi          movq $.LC0, %rdi          movq $0, %rax          call printf                            movq %r15, %rdx          movq %r14, %rsi          movq $.LC1, %rdi          movq $0, %rax          call printf            movq %r15, %rax          popq %r15          popq %r14          popq %r13          popq %r12          popq %rbx            leave               #return stack to original values          ret             #return      .size inventory, .-inventory    #required directive                    

I run the program, result is: r14 is getting the highest variation correctly, but LC0 prints correct highest variability (r14) but empty name (r15), and the C program that is trying to print the name stored in rax is also empty, the print statement prints:

The maximum variation is 65534 from

instead, it should print:

The maximum variation is 65534 from Mount Everst

The name is not being printed as you can see from above.

The main c program that calls inventory looks like this:

struct Device *worst = inventory(pointers, count);    printf("The worst is %s\n", worst->name);  

So, the output from the main program prints as following: The worst is

in other words, worst->name is not being printed at all.

after Further trouble shooting, I found out that r15 has the correct pointer, and its adjustment and avg values are correct, it is just name is empty string, any idea why? maybe since the name is a char array, and it is not being copied correctly?

Thanks!

https://stackoverflow.com/questions/67014883/assembly-how-to-return-a-pointer April 09, 2021 at 11:57AM

没有评论:

发表评论