2

I have an assembly code (hello1.s) where global label A_Td is defined and I want to access all the long data values defined with global label A_Td from/inside C program.

.file   "hello1.s"
.globl  A_Td
.text
.align  64
A_Td:
    .long   1353184337,1353184337
    .long   1399144830,1399144830
    .long   3282310938,3282310938
    .long   2522752826,2522752826
    .long   3412831035,3412831035
    .long   4047871263,4047871263
    .long   2874735276,2874735276   
    .long   2466505547,2466505547

As A_Td is defined in text section, so it is placed in code section and only one copy is loaded into memory.

Using yasm , I have generated hello1.o file

yasm -p gas -f elf32 hello1.s 

Now, to access all the long data using global label A_Td , I have written following C code (test_glob.c) taking clue from here global label.

//test_glob.c
extern A_Td ;

int main()
{
    long *p;
    int i;
    p=(long *)(&A_Td);
    for(i=0;i<16;i++)
    {
        printf("p+%d %p %ld\n",i, p+i,*(p+i));
    }
    return 0;
}

Using following command I have compiled C program and then run the C code.

gcc hello1.o test_glob.c 
./a.out

I am getting following output

p+0 0x8048400 1353184337
p+1 0x8048404 1353184337
p+2 0x8048408 1399144830
p+3 0x804840c 1399144830  -----> correct till this place
p+4 0x8048410 -1012656358 -----> incorrect value retrieved from this place
p+5 0x8048414 -1012656358
p+6 0x8048418 -1772214470
p+7 0x804841c -1772214470
p+8 0x8048420 -882136261
p+9 0x8048424 -882136261
p+10 0x8048428 -247096033
p+11 0x804842c -247096033
p+12 0x8048430 -1420232020
p+13 0x8048434 -1420232020
p+14 0x8048438 -1828461749
p+15 0x804843c -1828461749

ONLY first 4 long values are correctly accessed from C program. Why this is happening ?

What needs to be done inside C program to access the rest of data correctly ?

I am using Linux. Any help to resolve this issue or any link will be a great help. Thanks in advance.

bholanath
  • 1,699
  • 1
  • 22
  • 40

1 Answers1

1

How many bytes does "long" have in this system?

It seems to me that printf interprets the numbers as four byte signed integers, where the value 3282310938 has the hex value C3A4171A, which is above 7FFFFFFF (in decimal: 2147483647) which is the largest four byte positive signed number, and hence a negative value -1012656358. I assume that the assembler just interprets these four byte numbers as unsigned.

If you would use %lu instead of %ld, printf would interpret the numbers as unsigned, and should show what you expected.

FrankPl
  • 573
  • 4
  • 19
  • @FrankPI, in my system sizeof(long) returns 4, means long takes 4bytes. – bholanath Oct 06 '17 at 12:28
  • @bholanath: and what are the min and max values of a **signed** 32bit int? – Mat Oct 06 '17 at 12:30
  • @FrankPI, I got the right value printed as hex as you pointed out using %lx instead of %ld. Thank you for your prompt answer. – bholanath Oct 06 '17 at 12:32
  • @FrankPI, yes use of %lu gives the correct output . – bholanath Oct 06 '17 at 12:33
  • @bholanath: `.long` in x86 GAS assembly is *always* 32-bit, even when C `long` is 64-bit. You happened to get lucky here, but you need to read the manual for your assembler. e.g. https://sourceware.org/binutils/docs/as/Long.html says it's a synonym for `.int`, and the size and byte-order depends on the target. `.quad` is 8 bytes. Hmm, I can't actually find if/where it says that `.long` is 4 bytes for x86. You'd think the i386 section would say, but it doesn't: https://sourceware.org/binutils/docs/as/i386_002dDependent.html – Peter Cordes Oct 07 '17 at 03:47