I understand the basic layout (given a typical c++ implementation) of class instance members, but say you have MyClass with int num as a member, and you create an instance of it, how is the specific address of the member in memory handled at run time?
I'll be clearer with an example:
class MyClass
{
int num;
int num2;
int num3;
public:
void setNum(); //always sets num to 10
};
Then you call setnum, how does it know what memory to set to 10?
The memory layout for MyClass might look like
class MyClass size(12):
+---
0 | num
4 | num1
8 | num2
+---
So is it as simple as when setNum gets called with the hidden pointer to your instance of myclass for member access it gets written based on offest? forexample myclasspointer+4?
EDIT clarification how does it decide where to write to? failed copypaste left the vftable in there. I totally imagine its gonna just be a known offset right?
Or is it something more complex?
Apologizing for unclear terminallogy I rarely know how to phrase a question right...
The compiler will know the contents of the class (or struct), and most importantly the offsets of the different member variables. the setNum function is given a this pointer as a "hidden" argument, and the compiler will take the this variable and add the offset for num.
Exactly how this happens depends on the compiler. In LLVM, it would use a getelementptr VM instruction, which understands the structure and, given a base-address, adds the offset given by the index. This will then translate to some sort of instruction that takes the this and either a direct offset addition in a single instruction, or two instructions to load the pointer and then add the offset - depending a little bit on the architecture, and what the next instructions "need".
Since the num member is the first member in the struct, it will be zero, so on x86-64, compiled with clang++ -O1, we get this disassembly:
_ZN7MyClass6setNumEv: # #_ZN7MyClass6setNumEv
movl $10, (%rdi)
retq
In other words, move the number 10 into the address of this (in %rdi - first argument on a Linux machine).
The LLVM IR shows better what goes on:
%class.MyClass = type { i32, i32, i32 }
; Function Attrs: nounwind uwtable
define void #_ZN7MyClass6setNumEv(%class.MyClass* nocapture %this) #0 align 2 {
entry:
%num = getelementptr inbounds %class.MyClass* %this, i64 0, i32 0
store i32 10, i32* %num, align 4, !tbaa !1
ret void
}
The class contains 3 i32 (32 bit integers), and the function takes a this pointer, it then uses getelementptr to get the first element (element 0). Yes, there's one more argument than you'd expect. That's how LLVM works ;)
Then a store instruction for the value 10 into the %num calculated address.
If we change the code in setNum so that it stores 10 into num2 instead, we get:
define void #_ZN7MyClass6setNumEv(%class.MyClass* nocapture %this) #0 align 2 {
entry:
%num2 = getelementptr inbounds %class.MyClass* %this, i64 0, i32 2
store i32 10, i32* %num2, align 4, !tbaa !1
ret void
}
Note the change of the last number into getelementptr.
As assembly code it becomes:
_ZN7MyClass6setNumEv: # #_ZN7MyClass6setNumEv
movl $10, 8(%rdi)
retq
(As it currently stands, in Revision 2 of the original question, your class MyClass has a size of 12, 3 * 4 bytes, not 8 like your text says).
Related
I'm writing a C++ state machine for Cortex-M4.
I use ARM GCC 11.2.1 (none).
I'm making a comparison between C and C++ output assembly.
I have the following C++ code godbolt link
struct State
{
virtual void entry(void) = 0;
virtual void exit(void) = 0;
virtual void run(void) = 0;
};
struct S1 : public State
{
void entry(void)
{
}
void exit(void)
{
}
void run(void)
{
}
};
S1 s1;
The assembly output is:
S1::entry():
bx lr
S1::exit():
bx lr
S1::run():
bx lr
vtable for S1:
.word 0
.word 0
.word S1::entry()
.word S1::exit()
.word S1::run()
s1:
.word vtable for S1+8
The only difference from C version of this code is the 2 lines .word 0:
vtable for S1:
.word 0
.word 0
What does that mean and what does it do?
Here's the C version of the code above I wrote.
godbolt link
The C++ ABI for ARM and the GNU C++ ABI define which entries must appear in the virtual table.
In the case of your code, the first two entries are the offset to the top of the vtable and the typeinfo pointer. These are zero for now, but may be overwritten if required (eg: if a further derived class is made).
It means the assembler should output the word number 0.
The assembler basically goes through the file from top to bottom, and for each instruction, it calculates the bytes for that instruction (always 4 bytes on ARM), and writes it into the output file.
.word just tells it to output a particular number as 4 bytes. In this case 0.
In LLVM IR, if I define printf as a single arg func, I'm able to use it. However, if I define it as vararg, it gives an error:
#msg = constant [13 x i8] c"hello world\0A\00"
declare i32 #printf(i8*) ; works
;declare i32 #printf(i8*, ...) ; error: '#printf' defined with type 'i32 (i8*, ...)*'
; call i32 #printf(i8* %msg)
define i32 #main () {
%msg = getelementptr [13 x i8]* #msg, i64 0, i64 0
call i32 #printf(i8* %msg)
ret i32 0
}
How do I tell LLVM IR that printf is vararg, but call it with only one argument?
Note this passage from the description of the call instruction in the LLVM Language Reference (emphasis mine):
'fnty': shall be the signature of the function being called. The argument types must match the types implied by this signature. This type can be omitted if the function is not varargs.
So if the function is variadic, you do need to provide the function type as part of the call instruction.
The below bitcast instruction is throwing me an Illegal Bitcast error, can someone point what the problem is?
%opencl.image1d_ro_t = type opaque
%struct.dev_image_t = type { i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }
%astype = bitcast %opencl.image1d_ro_t addrspace(1)* %image to %struct.dev_image_t*
You're casting from address space 1 to the default address space, 0. That won't work, as the documentation says. Each address space is independent.
Address spaces are meant for things like programs that have some garbage-collected and some manually managed memory. The pointer points to two profoundly different kinds of memory.
I have a code that allocates memory, copies some buffer to that allocated memory and then it jumps to that memory address.
the problem is that I cant jump to the memory address. Im using gcc and __asm__ but I cant call that memory address.
I want to do something like:
address=VirtualAlloc(NULL,len+1, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
dest=strncpy(address, buf, len);
And then I want to do this in ASM:
MOV EAX, dest
CALL EAX.
I've tried something like:
__asm__("movl %eax, dest\n\t"
"call %eax\n\t");
But it does not work.
How can I do it?
There is usually no need to use asm for this, you can simply go through a function pointer and let the compiler take care of the details.
You do need to use __builtin___clear_cache(buf, buf+len) after copy machine code to a buffer before you dereference a function-pointer to it, otherwise it can be optimized away as a dead store.. x86 has coherent instruction caches so it doesn't compile to any extra instructions, but you still need it so the optimizer knows what's going on.
static inline
int func(char *dest, int len) {
__builtin___clear_cache(dest, dest+len); // no instructions on x86 but still needed
int ret = ((int (*)(void))dest)(); // cast to function pointer and deref
return ret;
}
compiles with GCC9.1 -O2 -m32 to
func(char*, int):
jmp [DWORD PTR [esp+4]] # tailcall
Also, you don't actually need to copy a string, you can just mprotect or VirtualProtect the page it's in to make it executable. But if you want to make sure it does stop at the first 0 byte to test your shellcode, then sure copy it.
If you nevertheless insist on inline asm, you should know that gcc inline asm is a complex thing. Also, if you expect the function to return, you should really make sure it follows the calling convention, in particular it preserves the registers it should.
AT&T syntax is op src, dst so your mov was actually a store to the global symbol dest.
That said, here is the answer to the question as worded:
int ret;
__asm__ __volatile__ ("call *%0" : "=a" (ret) : "0" (dest) : "ecx", "edx", "memory");
Explanation: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
call *%0 = the %0 refers to the first substitued argument, the * is standard gas syntax for indirect call
"=a" (ret) = output argument in eax register should be assigned to variable ret after the block
"0" (dest) = input argument in the same place as output argument 0 (which is eax) should be loaded from dest before the block
"ecx", "edx" = tell the compiler these registers may be altered by the asm block, as per normal calling convention.
"memory" = tell the compiler the asm block might make unspecified modifications to memory, so don't cache anything
Note that in x86-64 System V (Linux / OS X), it's not safe to make a function call from inline asm like this. There's no way to declare a clobber on the red zone below RSP.
Compiler: gcc 4.7.1, 32bit, ubuntu
Here's an example:
int main(void)
{
unsigned int mem = 0;
__asm volatile
(
"mov ebx, esp\n\t"
"mov %0, [ds : ebx]\n\t"
: "=m"(mem)
);
printf("mem = 0x%08x\n", mem);
return 0;
}
gcc -masm=intel -o app main.c
Assembler messages: invalid use of register!
As I know, ds and ss point to the same segment. I don't know why I can't use [ds : ebx] logical address for addressing.
Your code has two problems:
One: the indirect memory reference should be:
mov %0, ds : [ebx]
That is, with the ds out of the brackets.
Two: A single instruction cannot have both origin and destination in memory, you have to use a register. The easiest way would be to indicate =g that basically means whatever, but in your case it is not possible because esp cannot be moved directly to memory. You have to use =r.
Three: (?) You are clobbering the ebx register, so you should declare it as such, or else do not use it that way. That will not prevent compilation, but will make your code to behave erratically.
In short:
unsigned int mem = 0;
__asm volatile
(
"mov ebx, esp\n\t"
"mov %0, ds : [ebx]\n\t"
: "=r"(mem) :: "ebx"
);
Or better not to force to use ebx, let instead the compiler decide:
unsigned int mem = 0, temp;
__asm volatile
(
"mov %1, esp\n\t"
"mov %0, ds : [%1]\n\t"
: "=r"(mem) : "r"(temp)
);
BTW, you don't need the volatile keyword in this code. That is used to avoid the assembler to be optimized away even if the output is not needed. If you write the code for the side-effect, add volatile, but if you write the code to get an output, do not add volatile. That way, if the optimizing compiler determines that the output is not needed, it will remove the whole block.