我想学习C调用约定.为此,我编写了以下代码:
#include <stdio.h>
#include <stdlib.h>
struct tstStruct
{
void *sp;
int k;
};
void my_func(struct tstStruct*);
typedef struct tstStruct strc;
int main()
{
char a;
a = 'b';
strc* t1 = (strc*) malloc(sizeof(strc));
t1 -> sp = &a;
t1 -> k = 40;
my_func(t1);
return 0;
}
void my_func(strc* s1)
{
void* n = s1 -> sp + 121;
int d = s1 -> k + 323;
}
Run Code Online (Sandbox Code Playgroud)
然后我使用GCC使用以下命令:
gcc -S test3.c
Run Code Online (Sandbox Code Playgroud)
并想出了它的装配.我不会显示我得到的整个代码,而是粘贴函数my_func的代码.就是这个:
my_func:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16 …Run Code Online (Sandbox Code Playgroud) 关于如何使用Assembly将字符打印到屏幕上我有点困惑.该架构是x86(linux).可以调用其中一个C函数还是有更简单的方法?我想输出的字符存储在寄存器中.
谢谢!
大家好。
所以我正在学习汇编。
按照我通常学习的任何新语言的学习步骤,我已经到达了使用程序集的网络。
遗憾的是,情况不太好,因为我在第 0 步几乎失败了,这将获得一个可以开始通信的套接字。
汇编代码应大致等于以下 C 代码:
#include <stdio.h>
#include <sys/socket.h>
int main(){
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
}
Run Code Online (Sandbox Code Playgroud)
(让我们忽略它现在没有关闭套接字的事实。)
所以这是我到目前为止所做的:
在某些架构上——例如 x86-64 和 ARM——没有 socketcall() 系统调用;相反,socket(2)、accept(2)、bind(2) 等实际上是作为单独的系统调用实现的。
然而,在系统调用的原始列表中没有这样的调用——据我所知socket(),accept()、bind()、listen()、 等是来自libnet而不是来自内核的调用。这让我很困惑,所以我决定编译上面的C代码并使用strace. 这产生了以下结果:
套接字(PF_INET,SOCK_STREAM,IPPROTO_IP)= 3
虽然这并没有让我更接近于知道它是什么socket() ,但它确实解释了它的论点。对于女巫,我似乎没有找到合适的文档(再次)。我认为PF_INET,SOCK_STREAM,IPPROTO_IP就在被定义<sys/socket.h>,但我grep似乎对他们-ing没有发现使用的东西。所以我决定通过gdb与disass main查找值一起使用来实现它。这给出了以下输出:
汇编代码转储功能主要:0x00000000004004fd …
我在Linux内核模块内调用系统调用时遇到一些困难.系统调用已经过测试,并且可以从标准的c用户空间程序中正常工作,但我似乎无法获得内核模块来编译和运行它们.
在我的用户程序中,我包含以下代码,系统调用有效:
#include <linux/unistd.h>
#define __NR_sys_mycall 343
extern long int _syscall(long int_sysno,...)__THROW;
//and then a simple call is done as such
long value = syscall(__NR_sys_mycall);
printf("The value is %ld\n",value);
Run Code Online (Sandbox Code Playgroud)
但是当我在我的Linux内核模块中尝试相同的事情时,我得到了一堆错误,或者说错误:隐式声明函数'syscall'(如果我不包括_syscall定义)或一长串关于语法的错误if我...所以我的假设是我需要内核空间版本来调用系统调用.我是对还是错?
//My LKM code
#include <linux/module.h>
#include <linux/unistd.h>
#define __NR_sys_mycall 343
static int start_init(void)
{
long value = syscall(__NR_sys_mycall);
printk("The value is %ld\n",value);
return 0;
}
static void finish_exit(void)
{
printk("Done!\n");
}
module_init(start_init);
module_exit(finish_exit);
Run Code Online (Sandbox Code Playgroud) 有一个问题让我很困惑.
int main(int argc, char *argv[])
{
int i = 12345678;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
int main(int argc, char *argv[])
{
int i = 0;
return 0;
}
Run Code Online (Sandbox Code Playgroud)

程序总共具有相同的字节.为什么?
那个字面值确实存储在哪里?文字段或其他地方?

大家晚上好。我刚刚开始学习汇编语言,并且在网上找到了非常好的示例可以遵循。有人建议我使用 NASM 开始学习,但我发现的例子我看到他们使用 8086 汇编器。当我遵循这些示例时,我注意到如果我使用 NASM,它们不会在 Linux 终端上运行,但是如果我安装了 8086 汇编器模拟器,它确实可以工作。
我的问题是:NASM 和 8086 汇编器有什么区别吗?对我来说它们应该是同一件事,因为它是汇编代码。如果没有,有谁可以解释一下两者之间有什么区别吗?以及为什么它们不在 NASM 和 8086 上运行相同的代码
这是我跟踪的代码,它确实在 8086 汇编器上运行,但不在 Linux 上的 NASM 上运行
DATA SEGMENT
NUM1 DB ?
NUM2 DB ?
RESULT DB ?
MSG1 DB 10,13,"ENTER FIRST NUMBER TO ADD : $"
MSG2 DB 10,13,"ENTER SECOND NUMBER TO ADD : $"
MSG3 DB 10,13,"RESULT OF ADDITION IS : $"
ENDS
CODE SEGMENT
ASSUME DS:DATA CS:CODE
START:
MOV AX,DATA
MOV DS,AX
LEA DX,MSG1
MOV AH,9
INT 21H
MOV …Run Code Online (Sandbox Code Playgroud) 使用以下命令在我的Mac计算机上运行此代码:
nasm -f macho64 -o max.a maximum.asm
Run Code Online (Sandbox Code Playgroud)
这是我尝试在计算机上运行的代码,该代码在数组中找到最大的数字。
section .data
data_items:
dd 3,67,34,222,45,75,54,34,44,33,22,11,66,0
section .text
global _start
_start:
mov edi, 0
mov eax, [data_items + edi*4]
mov ebx, eax
start_loop:
cmp eax, 0
je loop_exit
inc edi
mov eax, [data_items + edi*4]
cmp eax, ebx
jle start_loop
mov ebx, eax
jmp start_loop
loop_exit:
mov eax, 1
int 0x80
Run Code Online (Sandbox Code Playgroud)
错误:
maximum.asm:14: error: Mach-O 64-bit format does not support 32-bit absolute addresses
maximum.asm:21: error: Mach-O 64-bit format does not support 32-bit absolute …Run Code Online (Sandbox Code Playgroud) 我无法找到在 MacOS 上编写 64 位程序集的良好文档。
64位 SysV ABI在 A.2.1 节中说了以下内容,并且此 SO 帖子引用了它:
系统调用是通过 syscall 指令完成的。内核销毁寄存器%rcx 和%r11。
从系统调用返回,寄存器 %rax 包含系统调用的结果。-4095 到 -1 之间的值表示错误,它是 -errno。
这两句话在 Linux 上没问题,但在 macOS Sierra 上却是错误的,代码如下:
global _start
extern _exit
section .text
_start:
; Align stack to 16 bytes for libc
and rsp, 0xFFFFFFFFFFFFFFF0
; Call write
mov rdx, 12 ; size
mov rsi, hello ; buf
mov edi, 1 ; fd
mov rax, 0x2000004 ; write ; replace to mov rax, 0x1 …Run Code Online (Sandbox Code Playgroud) 在《低级编程:英特尔® 64 位架构上的 C、汇编和程序执行》一书中,它说:
关于系统调用参数 系统调用的参数与函数的参数存储在一组不同的寄存器中。第四个参数存储在 中
r10,而函数接受第四个参数rcx!原因是
syscall指令隐式使用rcx. 系统调用不能接受超过六个参数。
您可以在此Stack Overflow 帖子中也看到这一点,
系统调用是通过 syscall 指令完成的。这会破坏 %rcx 和 %r11,以及 %rax,但保留其他寄存器。
我理解 clobberingrax存储返回码,但为什么是rcx, 并且r11clobbered in syscall?是否有破坏rcx/的特定系统调用的列表r11?有没有关于破坏的约定?它们在任何系统调用中都被认为是安全的吗?
让我们假设这个结构:
typedef struct mytest_t {
uint8_t field1;
uint32_t field2;
uint64_t field3;
uint64_t field4;
uint16_t field5;
uint32_t field6;
} mytest_t;
Run Code Online (Sandbox Code Playgroud)
还有一些想要创建此结构的函数(有点像一个对象):
int something_with(uint8_t field1, uint32_t field2, uint64_t field3, uint16_t field5) {
mytest_t *object = malloc(sizeof(mytest_t));
object->field1 = field1;
object->field2 = field2;
object->field3 = field3;
object->field4 = 0x12345678;
object->field5 = field5;
object->field6 = 42;
dosomethingwith(object);
return 0;
}
void initial() {
something_with(123, 456, 789, 456);
}
Run Code Online (Sandbox Code Playgroud)
这些功能纯粹是出于我的情况。此函数就像一个帮助程序,在代码中有一个单一的点,在该点上,对象被填充然后转发到其他对象。
注意:这个例子很小,假设参数要长2到3倍。
为了避免将大量参数传递给函数,并使调用变得冗长且难以阅读,我考虑将一个预填充的mytest_t结构作为参数传递(假设需要的字段正确填充)。
将struct作为值或指针传递会更好吗?取消引用所有字段的成本是多少?既然所有内容都在堆栈中,那有什么区别吗?编译器可以某种方式对其进行优化吗?
void initial() {
mytest_t source = {
.field1 = 123, …Run Code Online (Sandbox Code Playgroud)