.struct directive of GNU Assembler - How to instantiate a class instance? - linux

I'm trying to create an object-oriented class using GNU assembly for educational purposes. I have many questions regarding the use of the .struct directive:
It is said that this directive switch the code to the absolute section. Why is it named .struct then? Does it have anything to do with the struct of C?
What is the difference between using:
.set Object.data, 8
.set Object.func_pointer, 16
and using
.struct 0
Object:
Object.data:
.struct Object + 8
Object.func_pointer:
.struct Object.data + 8
Object_size = . - Object
Is this actually the way to use the .struct directive or it it a miss-use? To be honest I don't even know what I'm doing with the .struct directive. It looks useless to me?
The full code I provided below will allocate one instance of the Object class manually. If I want to instantiate the class whenever I want using a constructor function, do I need to move my object onto the stack and how would that be done? using .bss I can name my instance (for example test_object) but I'm not sure if I can name a stack address.
Full code so you can understand what I'm talking about: (GNU as, Linux x64)
.data
msg: .asciz "Hello world!\n"
.set msglen, . - msg
# CLASS struct
# This class struct only hold pointers to functions available for the class
.struct 0
Object:
# Class variables
Object.data:
.struct Object + 8
# Class pointers
Object.func_pointer:
.struct Object.data + 8
Object_size = . - Object
# Allocate Object_size bytes in the bss section to store the object instance
.bss
test_object:
.space Object_size
#----------------------------------------------------------------------------
# Code starts here
.text
#----------------------------------------------------------------------------
# Simple hello world function used as the target
hellofunc:
push %rbp
mov %rsp, %rbp
mov $1, %rax
mov $1, %rdi
mov $msg, %rsi
mov $msglen, %rdx
syscall
leave
ret
# Initiate the Object class by:
# Allocate a chunk of Object_size bytes on the stack
# Load value given in %rdi into Object.data
# Load the address of hellofunc into Object.func_pointer
initiate:
# Prologue
push %rbp
mov %rsp, %rbp
# Make %rdx point at the current object instance
mov $test_object, %rdx
# Load hellofunc address onto test_object.func_pointer
mov $hellofunc, %rax
mov %rax, Object.func_pointer(%rdx)
# Load data from %rdi onto test_object.data
mov %rdi, Object.data(%rdx)
# Test call to see if test_object.func_pointer is properly loaded
call *Object.func_pointer(%rdx)
# Epilogue
leave
ret
#---------------------------------------------------------------------------
# Main function
.globl _start
#---------------------------------------------------------------------------
_start:
mov $0xDEADBEEF, %rdi
call initiate
# return(0);
mov $60, %rax
mov $0, %rdi
syscall

I'm pretty sure all you're ever going to get out of any assembly language struct syntax is symbolic names for offsets, and a way to define them using the same .space directives that you'd normally use to reserve space for one static instance of a struct in the BSS. That's what NASM gives you, for example, and GAS's is even more rudimentary than that.
So yes, it's like a struct foo {int x; char c;}; definition in C: you use syntax that looks like declaring (reserving space for) global variables, but instead you're just defining the layout of a struct. (Except in GAS, you can only use .space and similar directives that can't take a value, no distinguishing one int from an array of 4 chars for example.)
But in GAS, it's so primitive that yes, it's just one way to
separately set a bunch of assemble-time constants with names like Object.func_pointer. You could do exactly the same thing with Object.func_pointer = 8, as well.
What is the difference between using: (.set) and (.struct)
Nothing. That's all it's doing for you. There isn't anything like a concept of a struct object, it's just one part of the tools that you can use to get symbolic names for offsets. They chose to call it .struct because that's one use-case.
However, you're repeating yourself unnecessarily by using .struct repeatedly (the example in the GAS manual does this, too; I don't know why). AFAIK you do have to repeat the struct name in each label (because GAS .struct syntax isn't very sophisticated), but you can use .space instead of having to name the previous field.
.struct 0
Object:
# .space 4
Object.obdata:
.space 8
Object.func_pointer:
.space 8
Object_size = . - Object
.text
mov $Object.obdata, %eax
mov $Object.func_pointer, %ecx
gcc -c foo.s && objdump -drwC -Mintel foo.o
...
0: b8 00 00 00 00 mov eax,0x0
5: b9 08 00 00 00 mov ecx,0x8
The names you choose to define after switching to the absolute section are 100% up to you, and not associated with any overall name for the struct.
NASM's struct support is a bit more sophisticated: you can define a layout in one spot, and use those member names when statically initializing an instance of it (e.g. in the .data section). Nasm - access struct elements by value and by address has an example. Note that it involves endstruc and iend directives, because you are actually defining a struct with members, not just separately setting a bunch of assemble-time constants with names like Object.func_pointer
Anything else like "constructors" you'll have to do yourself. e.g. writing the members into memory somewhere that you've decided is now an instance of a struct object.
This is assembly language, there is no compiler, any instructions you want in the final machine code you're going to have to write explicitly. (Unless you were using MASM, which magically adds instructions to your code in a few cases. GAS certainly doesn't; it was primarily designed to compiler compiler-generated asm. Deciding to emit instructions for a "constructor" at a certain point is something a compiler does internally, not via any special asm syntax. Same for hand-written asm.)

Related

Understanding assembly language _start label in a C program

I had written a simple c program and was trying to do use GDB to debug the program. I understand the use of following in main function:
On entry
push %ebp
mov %esp,%ebp
On exit
leave
ret
Then I tried gdb on _start and I got the following
xor %ebp,%ebp
pop %esi
mov %esp,%ecx
and $0xfffffff0,%esp
push %eax
push %esp
push %edx
push $0x80484d0
push $0x8048470
push %ecx
push %esi
push $0x8048414
call 0x8048328 <__libc_start_main#plt>
hlt
nop
nop
nop
nop
I am unable to understand these lines, and the logic behind this.
Can someone provide any guidance to help explain the code of _start?
Here is the well commented assembly source of the code you posted.
Summarized, it does the following things:
establish a sentinel stack frame with ebp = 0 so code that walks the stack can find its end easily
Pop the number of command line arguments into esi so we can pass them to __libc_start_main
Align the stack pointer to a multiple of 16 bits in order to comply with the ABI. This is not guaranteed to be the case in some versions of Linux so it has to be done manually just in case.
The addresses of __libc_csu_fini, __libc_csu_init, the argument vector, the number of arguments and the address of main are pushed as arguments to __libc_start_main
__libc_start_main is called. This function (source code here) sets up some glibc-internal variables and eventually calls main. It never returns.
If for any reason __libc_start_main should return, a hlt instruction is placed afterwards. This instruction is not allowed in user code and should cause the program to crash (hopefully).
The final series of nop instructions is padding inserted by the assembler so the next function starts at a multiple of 16 bytes for better performance. It is never reached in normal execution.
for gnu tools the _start label is the entry point of the program. for the C language to work you need to have a stack you need to have some memory/variables zeroed and some set to the values you chose:
int x = 5;
int y;
int fun ( void )
{
static int z;
}
all three of these variables x,y,z are essentially global, one is a local global. since we wrote it that way we assume that when our program starts x contains the value 5 and it is assumed that y is zero. in order for those things to happen, some bootstrap code is required and that is what happens (and more) between _start and main().
Other toolchains may choose to use a different label to define the entry/start point, but gnu tools use _start. there may be other things your tools require before main() is called C++ for example requires more than C.

Is my object oriented assembly right?

It's been some times that I started learning assembly and I often use object oriented concepts in my programs. I started doing this once I understood assembly well enough to imagine how objects work in machine code, but I do not know if my method is right or not.
Here is what my method looks like :
1. I define constants representing the relative adresses of each member of a class using the assembler constant directive (here gas x86-64).
.equ HUMAN_ID,0
.equ HUMAN_AGE,8
.equ HUMAN_NAME,16
.equ HUMAN_SIZE,24 # Size of object is 24 bytes
2. I allocate memory for the object and save the address in a pointer memory location.
movq $HUMAIN_SIZE,%rcx
call malloc # I avoid getting into systems specifics so I use C library
movq %rax,pointer
3. To access it, I dereference the pointer and use the relative address of a member to access it.
movq pointer,%rbx
movq $25,HUMAN_AGE(%rbx) # Set age to 25
movq HUMAN_AGE(%rbx),%rax # Get age into rax
Is this right? Do you have any advice? Thank you

Confused about AT&T Assembly Syntax for addressing modes vs. jmp and far jmp

In AT&T Assembly Syntax, literal values must be prefixed with a $ sign
But, in Memory Addressing, literal values do not have $ sign
for example:
mov %eax, -100(%eax)
and
jmp 100
jmp $100, $100
are different.
My question is why the $ prefix so confusing?
jmp 100 is a jump to absolute address 100, just like jmp my_label is a jump to the code at my_label. EIP = 100 or EIP = the address of my_label.
(jmp 100 assembles to a jmp rel32 with a R_386_PC32 relocation, asking the linker to fill in the right relative offset from the jmp instruction's own address to the absolute target.)
So in AT&T syntax, you can think of jmp x as sort of like an LEA into EIP.
Or another way to think of it is that code-fetch starts from the specified memory location. Requiring a $ for an immediate wouldn't really make sense, because the machine encoding for direct near jumps uses a relative displacement, not absolute. (http://felixcloutier.com/x86/JMP.html).
Also, indirect jumps use a different syntax (jmp *%eax register indirect or jmp *(%edi, %ecx, 4) memory indirect), so a distinction between immediate vs. memory isn't needed.
But far jump is a different story.
jmp ptr16:32 and jmp m16:32 are both available in 32-bit mode, so you do need to distinguish between ljmp *(%edi) vs. ljmp $100, $100.
Direct far jump (jmp far ptr16:32) does take an absolute segment:offset encoded into the instruction, just like add $123, %eax takes an immediate encoded into the instruction.
Question: My question is why the prefixed $ so confused ?
$ prefix is used to load/use the value as is.
example:
movl $5, %eax #copy value 5 to eax
addl $10,%eax # add 10 + 5 and store result in eax
$5, $10 are values (constants) and are not take from any external source like register or memory
In Memory addressing, Specifically "Direct addressing mode" we want to use the value stored in particular memory location.
example:
movl 20, %eax
The above would get the value stored in Memory location at 20.
Practially since memory locations are numbered in hexadecimal (0x00000000 to 0xfffffffff), it's difficult to specify the memory locations in hexadecimals in instructions. So we assign a symbol to the location
Example:
.section .data
mydata:
long 4
.section .text
.globl _start
_start
movl mydata, %eax
In the above code, mydata is symbolic representation given a particular memory location where value "4" is stored.
I hope the above clears your confusion.

Linux X86-64 assembly and printf

I am reading some linux assembly manuals and found idea about using printf() function. I need it to output register values for debugging reasons in binary form to terminal, but now I am tried simply to test that function with text.
I am stuck, because of segfault when I am using pushq instead of pushl. How can I change this program to output strings and binary form of registers?
.data
input_prompt:
.string "Hello, world!"
printf_format:
.string "%5d "
printf_newline:
.string "\n"
size:
.long 0
.text
.globl main
main:
pushq $input_prompt
call printf
movl $0, %eax
ret
It was compiled by GCC as:
gcc tmp.S -o tmp
Linux (and Windows) x86-64 calling convention has the first few arguments not on the stack, but in registers instead
See http://www.x86-64.org/documentation/abi.pdf (page 20)
Specifically:
If the class is MEMORY, pass the argument on the stack.
If the class is INTEGER, the next available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9 is used.
If the class is SSE, the next available vector register is used, the registers are taken in the order from %xmm0 to %xmm7.
If the class is SSEUP, the eightbyte is passed in the next available eightbyte chunk of the last used vector register.
If the class is X87, X87UP or COMPLEX_X87, it is passed in memory.
The INTEGER class is anything that will fit in a general purpose register, so that's what you would use for string pointers as well.

Assembly - Thread Safe Local Variables

I'm trying to have thread-safe local variables in an assembly program.
I've searched on the net, but I haven't found anything simple.
I'm currently using GCC assembler, as the program is a mix of C code and assembly, but the final program will contain code for multiple-platforms / calling conventions.
For now, I've declared my variables using the .lcomm pseudo-op.
As I understand it, those variables will be placed in the .bss section.
So I guess they will be shared by all threads.
Is there a way to have a kind of TLS variables directly in assembly, or should I use platform-specific implementations, like pthread or __declspec on Windows?
Hope it's clear enough. Don't hesitate to ask if more information is needed.
Thanks to everyone,
EDIT
Here's the code in question:
.lcomm stack0, 8
.lcomm stack1, 8
.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:
pushq %rbp
movq %rsp, %rbp
xor %rax, %rax
popq stack0( %rip )
popq stack1( %rip )
callq *%rdi
pushq stack1( %rip )
pushq stack0( %rip )
leave
ret
Basically, it's used to redirect a call to a C function.
The C prototype is:
extern uint64_t XSRuntime_CallMethod( void ( *m )( void * self, ... ), ... );
It takes a function pointer as first argument, hence the callq *%rdi, as I'm testing this with system V ABI.
The assembly code is very simple, and I'd like to keep it that way, so it can be easily maintainable.
The question is: how to make the stack0 and stack1 variables thread safe.
Not that familiar with assembler so:
.lcomm stack0, 8
.lcomm stack1, 8
.globl _XSRuntime_CallMethod
_XSRuntime_CallMethod:
pushq %rbp // save BP
movq %rsp, %rbp // load BP with SP
xor %rax, %rax // clear AX
popq stack0( %rip ) // pop return address into STACK0
popq stack1( %rip ) // pop flags into stack1
callq *%rdi // call the indirect procedure, so putting flags/return to XSRuntime_CallMethod onto stack
pushq stack1( %rip ) // put caller flags onto stack
pushq stack0( %rip ) // put caller return onto stack
leave // clean passed parameters from stack
ret // and back to caller
Is this how it works, yes??
If so, would it not be easier to just jump to the indirect procedure, rather than calling it? You then don't need any extra variables to hold the caller flags/return & the indirected procedure returns directly to the caller.
Just a suggestion - while since I did assembler.
If you have to store the caller address somewhere, dec the SP, (enter?), and use the stack frame. Anything else is likely to be thread-unsafe at some point.
Rgds,
Martin
Well, with a TLS maybee not thread-unsafe, but what about any recursive calls? You end up with another stack in the TLS to cover this, so you may as well use the 'SP' stack
Martin
How do you think the compiler implements thread-local variables? Try compiling such a program with -S or /FAs and you'll see. Hint: it has to rely on OS-specific APIs or other details to get access to TLS storage. Sometimes the preparation steps are hidden in the CRT but there's no single way to do it.
For example, here's how recent MSVC does it:
_TLS SEGMENT
?number##3HA DD 01H DUP (?) ; number
_TLS ENDS
EXTRN __tls_array:DWORD
EXTRN __tls_index:DWORD
_TEXT SEGMENT
[...]
mov eax, DWORD PTR __tls_index
mov ecx, DWORD PTR fs:__tls_array
mov edx, DWORD PTR [ecx+eax*4]
mov eax, DWORD PTR ?number##3HA[edx]
As you can see, it uses special variables which are initialized by the CRT.
On recent Linux, GCC can use TLS-specific relocations:
.globl number
.section .tbss,"awT",#nobits
number:
.zero 4
.text
[...]
movl %gs:number#NTPOFF, %eax
If you want portability, it's best not to rely on such OS-specific details but use a generic API such as pthread or use stack-based approach proposed by Martin. But I guess if you wanted portability you wouldn't use assembler :)
?? 'Classic' local variables, ie. parameters/variables/results accessed by stack offsets, are inherently thread-safe.
If you need a 'TLS' that is platform-agnostic, pass some suitable struct/class instance into all threads, either as the creation parameter, in a thread field before resuming all the threads, first message to the threads input queue or whatever...
Rgds,
Martin
As previously mentioned, local variables (stack-based) are inherently thread-safe because each thread has its own stack.
A thread-safe variable which is reachable by all threads (not stack-based) is probably best implemented using a spin-lock (or the equivalent in the Windows NT engine, a critical section). Such a variable must be locked before access, accessed and then unlocked. One variant could be that reads are free, but writes must be framed by locking/unlocking.
AFAIK only compilers themselves don't implement thread-safe variables. Instead they provide lib functions which access the required OS functionality.
You should probably be using(placing calls to) the TlsAlloc & TlsFree (or their other OS equivalents) to do something like this. the returned indices can be stored in global set once, read-only vars for easy use.
Depending on what the vars hold and what the code using them does, you might be able to get away with atomic ops, but that might yield problems of its own.

Categories

Resources