GNU Assembler (gas) on x86_64

D. Hugh Redelmeier hugh-pmF8o41NoarQT0dZR+AlfA at public.gmane.org
Wed Dec 20 05:46:29 UTC 2006


| From: Marc Lijour <marc-bbkyySd1vPWsTnJN9+BGXg at public.gmane.org>

| I try to follow Richard Blum "Assembly Language" book (Wrox) which focuses on 
| Linux and GNU gas -which is a very good thing.
| 
| However, my platform is x86_64, not i686. I could tweak the code a little bit 
| to avoid segfault by using information gathered at 

Why code for x86_64 if you don't have the manual?  At least some
x86_64 linux distros (eg. Fedora) let you compile and run i386 code.

| http://www.x86-64.org/documentation/assembly . Now the code looks like this:
| 
| # Using printf from libc
| .section .data
| output:
|         .asciz "The processor Vendor ID is '%s'\n"
| 
| .section .bss
|         .lcomm  buffer, 12
| .section .text
| .globl _start
| _start:
|         nop
|         movq    $0, %rax
|         cpuid
|         movq    $buffer, %rdi
|         movq    %rbx, (%rdi)
|         movq    %rdx, 4 (%rdi)
|         movq    %rcx, 8 (%rdi)
|         pushq   $buffer
|         pushq   $output
|         call    printf
|         addq    $8, %rsp
|         pushq   $0
|         call    exit
| 
| The unmodified example from the book gives this result on Intel i686:
| $ ./cpuid2_i686
| The processor Vendor ID is 'GenuineIntel'
| 
| But the code above gives me this on my AMD64:
| $ ./cpuid2_x86_64
| AuthenticAMD
| 
| (followed by no newline)
| 
| Question: why is the string (label output) not used by printf??

I expect that you need to pay attention to the ABI (Application Binary
Interface).  This spells out coding conventions for subroutine calls,
among other things.

Google got me to http://www.x86-64.org/documentation/abi.pdf

Section 3.2 talks about the function calling sequence.

Section 3.2.3 talks about parameter passing.

The first pointer arg should be passed in %rdi.  The second should be
passed in %rsi.

Don't forget to terminate C strings with '\0'.

You can also find a manuals for the x86_64.  I used this one:
  http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf
I discovered (on page 365) that CPUID operates on 32-bit operands even
when the CPU is in 64-bit mode.  Page 102 explains CPUID without
making this explicit.

Here's my guess at what your code should look like (UNTESTED).
Warning: I've never written a line of x86_64 code in my life.  The
last Intel processor that I did much assembly for was the i8080.

.section .data
output:
        .asciz "The processor Vendor ID is '%s'\n"

.section .bss
# polite to align the buffer since it is accessed as 4-byte units.
	.align 4
# note: length needs to be 13 (room for '\0')
        .lcomm  buffer, 13
.section .text
.globl _start
_start:
# CPUID argument is only 32 bits.
        movl    $0, %eax
        cpuid
        movq    $buffer, %rsi
# CPUID results are only 32-bit units
        movl    %ebx, (%rsi)
        movl    %edx, 4 (%rsi)
        movl    %ecx, 8 (%rsi)
# terminate the string
	movb $0, 12(%rsi)
# printf second arg in %rdi
        movq   $output, %rdi
        call    printf

# exit(0)
	movq	$0, %rdi
        call    exit

Useful trick: write something in C and see what gcc comes up with (-S
flag causes it to compile to assembly code).

Problem: it seems to write bad assembler that gas apparently corrects.
I see movl used for 64-bit moves, for example.  A mystery that I won't
try to unravel.

Here's my sample C code:
    #include <stdio.h>

    int
    main()
    {
	printf("format %s\n", "arg");
	return 0;
    }
--
The Toronto Linux Users Group.      Meetings: http://gtalug.org/
TLUG requests: Linux topics, No HTML, wrap text below 80 columns
How to UNSUBSCRIBE: http://gtalug.org/wiki/Mailing_lists





More information about the Legacy mailing list